Skip to content

Commit 6ca22cb

Browse files
committed
feat: add alert dialog when error access camera
1 parent bb1d8bf commit 6ca22cb

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

app/analyze/page.tsx

+38-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
'use client';
22

33
import * as React from 'react';
4+
import Link from 'next/link';
45

56
import { analyzeFoodImageAction } from '~/app/analyze/actions';
67
import { Header } from '~/components/header';
78
import { Icons } from '~/components/icons';
9+
import {
10+
AlertDialog,
11+
AlertDialogAction,
12+
AlertDialogCancel,
13+
AlertDialogContent,
14+
AlertDialogDescription,
15+
AlertDialogFooter,
16+
AlertDialogHeader,
17+
AlertDialogTitle,
18+
} from '~/components/ui/alert-dialog';
819
import { Button } from '~/components/ui/button';
920
import {
1021
Sheet,
@@ -23,7 +34,10 @@ export default function AnalyzePage() {
2334
const [result, setResult] = React.useState<FoodAnalyzeResult | null>(null);
2435
const [isPending, startTransition] = React.useTransition();
2536

26-
const videoElementRef = useVideoStream();
37+
const [
38+
videoElementRef,
39+
{ error: videoStreamError, retry: retryVideoStream },
40+
] = useVideoStream();
2741
const [
2842
canvasElementRef,
2943
{ drawImageToCanvas, getImageFromCanvas, clearCanvas },
@@ -73,7 +87,7 @@ export default function AnalyzePage() {
7387
<div className="relative flex-1">
7488
<video
7589
ref={videoElementRef}
76-
className="absolute inset-0 h-full w-full flex-1 rounded-lg border object-cover"
90+
className="absolute inset-0 h-full w-full flex-1 rounded-lg border bg-muted object-cover"
7791
autoPlay
7892
muted
7993
/>
@@ -120,6 +134,28 @@ export default function AnalyzePage() {
120134
</div>
121135
</SheetContent>
122136
</Sheet>
137+
138+
<AlertDialog open={videoStreamError !== null}>
139+
<AlertDialogContent>
140+
<AlertDialogHeader>
141+
<AlertDialogTitle>
142+
Failed to Access Device Camera!
143+
</AlertDialogTitle>
144+
<AlertDialogDescription>
145+
Please make sure you have granted access to your device camera
146+
and try again
147+
</AlertDialogDescription>
148+
</AlertDialogHeader>
149+
<AlertDialogFooter>
150+
<AlertDialogCancel asChild>
151+
<Link href="/">Back</Link>
152+
</AlertDialogCancel>
153+
<AlertDialogAction onClick={retryVideoStream}>
154+
Try again
155+
</AlertDialogAction>
156+
</AlertDialogFooter>
157+
</AlertDialogContent>
158+
</AlertDialog>
123159
</div>
124160
</main>
125161
);

hooks/use-video-stream.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import * as React from 'react';
22

33
export function useVideoStream() {
44
const videoElementRef = React.useRef<HTMLVideoElement>(null);
5+
const [error, setError] = React.useState<Error | null>(null);
6+
const [retryCount, setRetryCount] = React.useState<number>(0);
57

68
React.useEffect(() => {
79
async function startVideo() {
@@ -16,14 +18,23 @@ export function useVideoStream() {
1618
});
1719

1820
videoElementRef.current.srcObject = mediaStream;
21+
22+
setError(null);
1923
} catch (error) {
20-
// TODO: show user friendly error
24+
if (error instanceof Error) {
25+
setError(error);
26+
}
2127
console.error(error);
2228
}
2329
}
2430

2531
startVideo();
26-
}, []);
32+
}, [retryCount]);
33+
34+
const retry = () => {
35+
setError(null);
36+
setRetryCount((count) => count + 1);
37+
};
2738

28-
return videoElementRef;
39+
return [videoElementRef, { error, retry }] as const;
2940
}

0 commit comments

Comments
 (0)