Skip to content

Commit 160c36f

Browse files
use query api
1 parent 39397d8 commit 160c36f

File tree

6 files changed

+92
-60
lines changed

6 files changed

+92
-60
lines changed

src/components/Spinner.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { LoaderCircleIcon } from "lucide-react";
2+
3+
export default function Spinner() {
4+
return (
5+
<div className="flex items-center justify-center">
6+
<LoaderCircleIcon size={16} className="animate-spin" />
7+
</div>
8+
);
9+
}

src/components/date-logs.tsx

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,54 @@
1-
import { Either } from "effect";
21
import { XIcon } from "lucide-react";
32
import { Button } from "react-aria-components";
43
import { useDeleteLog } from "../lib/hooks/use-delete-log";
54
import { useGetLogByDate } from "../lib/hooks/use-get-log-by-date";
65
import { textColor } from "../styles";
6+
import Spinner from "./Spinner";
77

88
export default function DateLogs({ date }: { date: string }) {
99
const [_, action, pending] = useDeleteLog();
10-
const logByDate = useGetLogByDate(date);
11-
return Either.isRight(logByDate) ? (
10+
const { error, data, loading } = useGetLogByDate(date);
11+
12+
if (loading) {
13+
return <Spinner />;
14+
} else if (error) {
15+
return <div>{error.message}</div>;
16+
}
17+
18+
return (
1219
<div className="flex flex-wrap items-center justify-center gap-2">
13-
{logByDate.right.map((log) => (
14-
<div
15-
key={log.logId}
16-
className={textColor({
17-
theme: log.color,
18-
className:
19-
"border rounded-md inline-flex items-center gap-x-2 px-2 py-1",
20-
})}
21-
>
22-
<form
23-
action={action}
24-
className="inline-flex items-center justify-center"
20+
{data.length === 0 ? (
21+
<span className="text-sm text-fuchsia/50">No activity</span>
22+
) : (
23+
data.map((log) => (
24+
<div
25+
key={log.logId}
26+
className={textColor({
27+
theme: log.color,
28+
className:
29+
"border rounded-md inline-flex items-center gap-x-2 px-2 py-1",
30+
})}
2531
>
26-
<input type="hidden" value={log.logId} name="log-id" />
27-
<Button
28-
type="submit"
29-
isDisabled={pending}
30-
className="text-sm hover:cursor-pointer"
32+
<form
33+
action={action}
34+
className="inline-flex items-center justify-center"
3135
>
32-
<XIcon
33-
size={16}
34-
className="hover:scale-125 transition-transform duration-150"
35-
/>
36-
</Button>
37-
</form>
38-
<span>{log.name}</span>
39-
</div>
40-
))}
36+
<input type="hidden" value={log.logId} name="log-id" />
37+
<Button
38+
type="submit"
39+
isDisabled={pending}
40+
className="text-sm hover:cursor-pointer"
41+
>
42+
<XIcon
43+
size={16}
44+
className="hover:scale-125 transition-transform duration-150"
45+
/>
46+
</Button>
47+
</form>
48+
<span>{log.name}</span>
49+
</div>
50+
))
51+
)}
4152
</div>
42-
) : (
43-
<div>{logByDate.left._tag}</div>
4453
);
4554
}

src/components/insert-activity.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
import { Either } from "effect";
21
import { Radio } from "react-aria-components";
32
import { useGetCategories } from "../lib/hooks/use-get-categories";
43
import { useInsertActivity } from "../lib/hooks/use-insert-activity";
54
import CategoryDot from "./category-dot";
5+
import Spinner from "./Spinner";
66
import { Button } from "./ui/button";
77
import { RadioGroup } from "./ui/radio-group";
88
import { FieldError, Input, Label, TextField } from "./ui/text-field";
99

1010
export default function InsertActivity() {
1111
const [, action, pending] = useInsertActivity();
12-
const categories = useGetCategories();
12+
const { data, error, loading } = useGetCategories();
1313

14-
if (Either.isLeft(categories)) {
15-
return <div>Loading...</div>;
14+
if (loading) {
15+
return <Spinner />;
16+
} else if (error) {
17+
return <div>{error.message}</div>;
1618
}
1719

1820
return (
@@ -25,7 +27,7 @@ export default function InsertActivity() {
2527

2628
<RadioGroup className="flex flex-wrap gap-2" name="category-id">
2729
<Label hidden>Category</Label>
28-
{categories.right.map((category) => (
30+
{data.map((category) => (
2931
<Radio
3032
key={category.categoryId}
3133
id={`${category.categoryId}`}

src/components/insert-log.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
1-
import { Either } from "effect";
21
import { PlusIcon } from "lucide-react";
32
import { Button } from "react-aria-components";
43
import { useGetActivities } from "../lib/hooks/use-get-activities";
54
import { useInsertLog } from "../lib/hooks/use-insert-log";
65
import { textColor } from "../styles";
6+
import Spinner from "./Spinner";
77

88
export default function InsertLog({ date }: { date: string }) {
9-
const activities = useGetActivities();
109
const [, action, pending] = useInsertLog(date);
11-
return Either.isRight(activities) ? (
10+
const { data, error, loading } = useGetActivities();
11+
12+
if (loading) {
13+
return <Spinner />;
14+
} else if (error) {
15+
return <div>{error.message}</div>;
16+
}
17+
18+
return (
1219
<div className="flex flex-wrap gap-2">
13-
{activities.right.map((activity) => (
20+
{data.map((activity) => (
1421
<div
1522
key={activity.activityId}
1623
className={textColor({
@@ -43,7 +50,5 @@ export default function InsertLog({ date }: { date: string }) {
4350
</div>
4451
))}
4552
</div>
46-
) : (
47-
<div>{activities.left._tag}</div>
4853
);
4954
}

src/lib/hooks/use-pglite-query.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { useLiveQuery } from "@electric-sql/pglite-react";
22
import type { Query } from "drizzle-orm";
33
import {
4-
Array,
54
Data,
65
Either,
76
flow,
7+
Match,
88
pipe,
99
Schema,
1010
type ParseResult,
@@ -31,21 +31,28 @@ export const useQuery = <A, I>(
3131
Schema.decodeEither(Schema.Array(schema)),
3232
Either.mapLeft((parseError) => new InvalidData({ parseError }))
3333
)
34-
)
35-
);
36-
};
37-
38-
export const useQuerySingle = <A, I>(
39-
...args: Parameters<typeof useQuery<A, I>>
40-
) => {
41-
const results = useQuery(...args);
42-
return pipe(
43-
results,
44-
Either.flatMap(
45-
flow(
46-
Array.head,
47-
Either.fromOption(() => new MissingData())
48-
)
49-
)
34+
),
35+
Either.match({
36+
onLeft: (_) =>
37+
Match.value(_).pipe(
38+
Match.tagsExhaustive({
39+
InvalidData: ({ parseError }) => ({
40+
error: parseError,
41+
loading: false as const,
42+
data: undefined,
43+
}),
44+
MissingData: (_) => ({
45+
loading: true as const,
46+
data: undefined,
47+
error: undefined,
48+
}),
49+
})
50+
),
51+
onRight: (rows) => ({
52+
data: rows,
53+
loading: false as const,
54+
error: undefined,
55+
}),
56+
})
5057
);
5158
};

src/routes/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function HomeComponent() {
2929
const { date } = Route.useSearch();
3030
return (
3131
<div className="mx-auto max-w-[32rem] py-12 flex flex-col gap-y-12">
32-
<div className="flex flex-col gap-y-8 items-center">
32+
<div className="flex flex-col gap-y-12 items-center">
3333
<div className="flex flex-col items-center gap-y-4">
3434
<Link
3535
to="."

0 commit comments

Comments
 (0)