Skip to content

Commit 0fc4160

Browse files
author
Alex Meah
committed
Task 2
1 parent 7e7f98a commit 0fc4160

6 files changed

Lines changed: 52 additions & 26 deletions

File tree

‎src/api/note/schema.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export type Notes = z.infer<typeof NotesSchema>;
1818
export const CreateNoteSchema = NoteSchema.pick({ title: true, content: true });
1919
export type CreateNote = z.infer<typeof CreateNoteSchema>;
2020

21-
export type NoteSearchParams = { search: string };
21+
export type NoteSearchParams = { search: string; favouritesOnly?: "true" | "false" };
2222

2323
export const FavouriteNoteSchema = z.object({
2424
isFavourite: z.boolean(),

‎src/components/Form.tsx‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import clsx from "clsx";
12
import type { ComponentPropsWithoutRef } from "react";
23

34
export const Label = ({ children, ...props }: ComponentPropsWithoutRef<"label">) => (
@@ -9,13 +10,19 @@ export const Label = ({ children, ...props }: ComponentPropsWithoutRef<"label">)
910
export const Input = (props: ComponentPropsWithoutRef<"input">) => (
1011
<input
1112
{...props}
12-
className="w-full max-w-sm p-2 leading-none border-2 rounded outline-none focus:border-amber-400"
13+
className={clsx(
14+
"w-full max-w-sm p-2 leading-none border-2 rounded outline-none focus:border-amber-400",
15+
props.className,
16+
)}
1317
/>
1418
);
1519

1620
export const Textarea = (props: ComponentPropsWithoutRef<"textarea">) => (
1721
<textarea
1822
{...props}
19-
className="w-full max-w-sm p-2 border-2 rounded outline-none focus:border-amber-400"
23+
className={clsx(
24+
"w-full max-w-sm p-2 border-2 rounded outline-none focus:border-amber-400",
25+
props.className,
26+
)}
2027
/>
2128
);

‎src/lib/helpers.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const boolAsString = (v: boolean) => (v ? "true" : "false");

‎src/mocks/handlers.ts‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,12 @@ export const handlers = [
2626
http.get(api.notes.getAll.url, ({ request }) => {
2727
const url = new URL(request.url);
2828
const search = url.searchParams.get("search");
29+
const favouritesOnly = url.searchParams.get("favouritesOnly") === "true";
30+
const notes = mockNotes
31+
.filter((n) => (search ? n.title.toLowerCase().includes(search.toLowerCase()) : true))
32+
.filter((n) => (favouritesOnly ? n.isFavourite : true));
2933

30-
if (search) {
31-
return HttpResponse.json(
32-
mockNotes.filter((n) => n.title.toLowerCase().includes(search.toLowerCase())),
33-
);
34-
}
35-
36-
return HttpResponse.json(mockNotes);
34+
return HttpResponse.json(notes);
3735
}),
3836
http.post(api.notes.create.url, async ({ request }) => {
3937
const newNote = CreateNoteSchema.safeParse(await request.json());

‎src/pages/Note/Note.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import toast from "react-hot-toast";
55
import { useParams } from "react-router-dom";
66
import invariant from "tiny-invariant";
77
import { api } from "../../api";
8-
import { type CreateNote, CreateNoteSchema, FavouriteNote } from "../../api/note/schema";
8+
import { type CreateNote, CreateNoteSchema, type FavouriteNote } from "../../api/note/schema";
99
import { Button } from "../../components/Button";
1010
import { Input, Textarea } from "../../components/Form";
1111
import { Heading } from "../../components/Typography";

‎src/pages/Notes/Notes.tsx‎

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@ import { ButtonLink } from "../../components/Button";
77
import { Input } from "../../components/Form";
88
import { Spinner } from "../../components/Icons";
99
import { Heading, Link } from "../../components/Typography";
10+
import { boolAsString } from "../../lib/helpers";
1011
import { CreateNoteForm } from "../CreateNote/CreateNoteForm";
1112

1213
export const Notes = () => {
1314
const queryClient = useQueryClient();
1415
const [search, setSearch] = useState("");
16+
const [favouritesOnly, setFavouritesOnly] = useState<boolean>(false);
1517
const {
1618
data: notes,
1719
isLoading,
1820
isFetching,
1921
isError,
2022
} = useQuery({
21-
...api.notes.getAll.query({ searchParams: { search } }),
23+
...api.notes.getAll.query({
24+
searchParams: { search, favouritesOnly: boolAsString(favouritesOnly) },
25+
}),
2226
placeholderData: keepPreviousData,
2327
});
2428
const { mutate, submittedAt } = useMutation({
@@ -37,23 +41,39 @@ export const Notes = () => {
3741
return (
3842
<section className="space-y-6">
3943
<div className="flex items-center justify-between">
40-
<Heading level={1}>Notes</Heading>
44+
<div className="flex items-center gap-4">
45+
<Heading level={1}>Notes</Heading>
46+
{isFetching && <Spinner />}
47+
</div>
4148
<ButtonLink to="/create">Create note</ButtonLink>
4249
</div>
4350

44-
<label htmlFor="search" className="sr-only">
45-
Filter notes
46-
</label>
47-
<div className="flex items-center gap-2">
48-
<Input
49-
placeholder="Filter notes..."
50-
type="text"
51-
name="search"
52-
id="search"
53-
value={search}
54-
onChange={(e) => setSearch(e.target.value)}
55-
/>
56-
{isFetching && <Spinner />}
51+
<div className="flex items-center gap-8">
52+
<div className="flex items-center gap-2">
53+
<label htmlFor="search" className="sr-only">
54+
Filter notes
55+
</label>
56+
<Input
57+
placeholder="Filter notes..."
58+
type="text"
59+
name="search"
60+
id="search"
61+
value={search}
62+
onChange={(e) => setSearch(e.target.value)}
63+
/>
64+
</div>
65+
66+
<div className="flex items-center gap-2">
67+
<label htmlFor="favs">Only favs</label>
68+
<Input
69+
className="w-fit"
70+
type="checkbox"
71+
name="favs"
72+
id="favs"
73+
checked={favouritesOnly}
74+
onChange={(e) => setFavouritesOnly(e.target.checked)}
75+
/>
76+
</div>
5777
</div>
5878

5979
<ul>

0 commit comments

Comments
 (0)