1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogBody,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
isValidFreezeDuration,
MAX_FREEZE_DURATION_SECONDS,
useFreezeFrameStore,
} from "@/actions/freeze-frame-store";
export function FreezeFrameDialog() {
const isOpen = useFreezeFrameStore((state) => state.isOpen);
const cancelDuration = useFreezeFrameStore((state) => state.cancelDuration);
return (
<Dialog
open={isOpen}
onOpenChange={(open) => {
if (!open) {
cancelDuration();
}
}}
>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>Freeze frame</DialogTitle>
<DialogDescription>
How long should the frozen frame stay on screen?
</DialogDescription>
</DialogHeader>
{isOpen && <FreezeFrameForm />}
</DialogContent>
</Dialog>
);
}
function FreezeFrameForm() {
const lastDurationSeconds = useFreezeFrameStore(
(state) => state.lastDurationSeconds,
);
const confirmDuration = useFreezeFrameStore((state) => state.confirmDuration);
const cancelDuration = useFreezeFrameStore((state) => state.cancelDuration);
const [value, setValue] = useState(String(lastDurationSeconds));
const seconds = Number(value);
const showError = value.trim() !== "" && !isValidFreezeDuration({ seconds });
const canConfirm = isValidFreezeDuration({ seconds });
const handleConfirm = () => {
if (canConfirm) {
confirmDuration({ seconds });
}
};
return (
<>
<DialogBody className="gap-3">
<Label htmlFor="freeze-frame-duration">Duration (seconds)</Label>
<Input
id="freeze-frame-duration"
value={value}
inputMode="decimal"
aria-invalid={showError}
onChange={(e) => setValue(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
handleConfirm();
}
}}
placeholder="e.g. 2.5"
/>
{showError && (
<p className="text-destructive text-xs">
Enter a duration greater than 0 and at most{" "}
{MAX_FREEZE_DURATION_SECONDS} seconds.
</p>
)}
</DialogBody>
<DialogFooter>
<Button
variant="outline"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
cancelDuration();
}}
>
Cancel
</Button>
<Button onClick={handleConfirm} disabled={!canConfirm}>
Freeze
</Button>
</DialogFooter>
</>
);
}
|