Skip to content

Commit 3c45112

Browse files
committed
improved date picker; added optimistic collection updates
1 parent bb03347 commit 3c45112

File tree

5 files changed

+47
-41
lines changed

5 files changed

+47
-41
lines changed

src/components/habit/card.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,9 @@ export const HabitCard: React.FC = () => {
6262
return (
6363
<div
6464
{...extraProps}
65-
className={cn(
66-
"habit-card rounded truncate w-full max-w-211 flex flex-col gap-1",
67-
{
68-
"min-h-40": !displayOptions.hideChart && !isReordering,
69-
},
70-
{ "cursor-move": isReordering },
71-
)}
65+
className={cn("habit-card rounded truncate w-full max-w-211 flex flex-col gap-1", {
66+
"min-h-40": !displayOptions.hideChart && !isReordering,
67+
})}
7268
>
7369
<div
7470
className={cn(

src/components/habit/date-picker.tsx

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { DateContext } from "@/components/date/context"
21
import { Button } from "@/components/ui/button"
32
import { Calendar } from "@/components/ui/calendar"
43
import {
@@ -9,20 +8,16 @@ import {
98
DialogTitle,
109
DialogTrigger,
1110
} from "@/components/ui/dialog"
12-
import { formatDate } from "@/lib/dates"
13-
import { ArrowRight, CalendarIcon, Undo2 } from "lucide-react"
11+
import { cn } from "@/lib/utils"
12+
import { ArrowRight, CalendarIcon, CalendarSearch, Undo2 } from "lucide-react"
1413
import React from "react"
1514

1615
import { useHabitContext } from "./context"
1716

1817
export const HabitDatePicker: React.FC = () => {
19-
const today = React.useContext(DateContext)
2018
const { selectedDate, setSelectedDate } = useHabitContext()
2119
const [open, setOpen] = React.useState(false)
2220

23-
const dateStr = formatDate(selectedDate ?? today)
24-
const todayStr = formatDate(new Date())
25-
2621
const handleSelect = (d: Date | undefined) => {
2722
setSelectedDate(d || new Date())
2823
setOpen(false)
@@ -34,7 +29,7 @@ export const HabitDatePicker: React.FC = () => {
3429
variant="ghost"
3530
size="sm"
3631
className="w-fit"
37-
disabled={dateStr === todayStr}
32+
disabled={selectedDate === undefined}
3833
onClick={() => setSelectedDate(undefined)}
3934
>
4035
<Undo2 />
@@ -44,8 +39,12 @@ export const HabitDatePicker: React.FC = () => {
4439
<DialogTrigger asChild>
4540
<div className="flex items-center gap-2">
4641
<Button variant="ghost" size="sm" className="w-fit">
47-
<CalendarIcon />
48-
{selectedDate?.toLocaleDateString()}
42+
<CalendarSearch
43+
className={cn({ "text-amber-600": selectedDate !== undefined })}
44+
/>
45+
{selectedDate === undefined
46+
? "Today"
47+
: selectedDate?.toLocaleDateString()}
4948
</Button>
5049
</div>
5150
</DialogTrigger>

src/components/habit/icon.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,20 @@ export const HabitIcon: React.FC<LucideProps> = (props) => {
1212
const color = colors.index[colors.fromString(habit.color)]
1313

1414
if (isFetching) {
15-
return <Loader2 {...props} className={cn("animate-spin", color.text, props.className)} />
15+
return (
16+
<Loader2
17+
data-testid="habit-icon-locader"
18+
{...props}
19+
className={cn("animate-spin", color.text, props.className)}
20+
/>
21+
)
1622
}
1723

18-
const className = cn(color.text, props.className)
24+
const className = cn(color.text, props.className, {
25+
"cursor-move": isReordering,
26+
})
27+
const finalProps = { ...props, className, "data-testid": "habit-icon" }
1928

20-
if (isReordering) return React.createElement(GripVertical, { ...props, className })
21-
return icons.render(habit.icon, { ...props, className })
29+
if (isReordering) return React.createElement(GripVertical, finalProps)
30+
return icons.render(habit.icon, finalProps)
2231
}

src/components/ordering/provider.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,19 @@ export const OrderingProvider: React.FC<React.PropsWithChildren> = ({ children }
7575
})
7676
}
7777

78+
const orderHabits = (isReordering: boolean) =>
79+
reorder(habits, completed, collection.order, isReordering)
80+
7881
const [isReordering, _setReordering] = React.useState(false)
79-
const [orderedNames, setOrderedNames] = React.useState<string[]>(
80-
reorder(habits, completed, collection.order, isReordering),
81-
)
82+
const [orderedNames, setOrderedNames] = React.useState<string[]>(orderHabits(isReordering))
8283

8384
React.useEffect(() => {
8485
setCompleted(new Set())
8586
}, [date])
8687

8788
React.useEffect(() => {
88-
setOrderedNames(reorder(habits, completed, collection.order, isReordering))
89-
}, [completed, habits])
89+
setOrderedNames(orderHabits(isReordering))
90+
}, [completed, habits, collection.order])
9091

9192
const handleDragEnd = (event: DragEndEvent) => {
9293
const { active, over } = event
@@ -105,7 +106,7 @@ export const OrderingProvider: React.FC<React.PropsWithChildren> = ({ children }
105106
const updateOrder = useUpdateOrder()
106107
const setReordering = (v: boolean) => {
107108
_setReordering(v)
108-
setOrderedNames(reorder(habits, completed, collection.order, v))
109+
setOrderedNames(orderHabits(v))
109110

110111
if (!v && orderChanged(collection.order, orderedNames)) {
111112
updateOrder.mutate(orderedNames)

src/lib/queries.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,16 @@ const usePushCollection = () => {
347347
const repo = useRepoContext()
348348
const { collection } = useCollectionContext()
349349
const octokit = useOctokit()
350+
const onSettled = useInvalidateCollection()
350351

351-
return (update: (c: Collection) => void, message: string) => {
352+
const mutate = (update: (c: Collection) => void, message: string) => {
352353
const copy = clone(CollectionSchema, collection)
353354

354355
update(copy)
355356
copy.sha = ""
356357

358+
client.setQueryData(["repo", repo.id, "collection"], copy)
359+
357360
return octokit.rest.repos.createOrUpdateFileContents({
358361
path: "collection.json",
359362
owner: account.login,
@@ -364,6 +367,8 @@ const usePushCollection = () => {
364367
headers: { "If-None-Match": "" },
365368
})
366369
}
370+
371+
return { mutate, onSettled }
367372
}
368373

369374
const useInvalidateCollection = () => {
@@ -374,41 +379,37 @@ const useInvalidateCollection = () => {
374379
}
375380

376381
export const useDeleteTags = () => {
377-
const pushCollection = usePushCollection()
378-
const invalidateCollection = useInvalidateCollection()
382+
const { mutate, onSettled } = usePushCollection()
379383

380384
return useMutation({
381385
mutationFn: (tags: string[]) =>
382-
pushCollection((c) => {
386+
mutate((c) => {
383387
for (const name of tags) {
384388
delete c.tags[name]
385389
}
386390
}, `deleted ${tags.length} tag(s)`),
387-
onSettled: invalidateCollection,
391+
onSettled,
388392
retry: handleError("Failed to delete tags", { maxFailures: 0 }),
389393
})
390394
}
391395

392396
export const useNewTag = () => {
393-
const pushCollection = usePushCollection()
394-
const invalidateCollection = useInvalidateCollection()
397+
const { mutate, onSettled } = usePushCollection()
395398

396399
return useMutation({
397400
mutationFn: (tag: Tag) =>
398-
pushCollection((c) => (c.tags[tag.name] = tag), `created tag - ${tag.name}`),
399-
onSettled: invalidateCollection,
401+
mutate((c) => (c.tags[tag.name] = tag), `created tag - ${tag.name}`),
402+
onSettled,
400403
retry: handleError("Failed to create tag", { maxFailures: 0 }),
401404
})
402405
}
403406

404407
export const useUpdateOrder = () => {
405-
const pushCollection = usePushCollection()
406-
const invalidateCollection = useInvalidateCollection()
408+
const { mutate, onSettled } = usePushCollection()
407409

408410
return useMutation({
409-
mutationFn: (order: string[]) =>
410-
pushCollection((c) => (c.order = order), `reordered habits`),
411-
onSettled: invalidateCollection,
411+
mutationFn: (order: string[]) => mutate((c) => (c.order = order), `reordered habits`),
412+
onSettled,
412413
retry: handleError("Failed to update order", { maxFailures: 0 }),
413414
})
414415
}

0 commit comments

Comments
 (0)