1- import { useMutation , useQuery } from "@tanstack/react-query" ;
21import { AlertCircleIcon , ArrowRightIcon , CheckIcon } from "lucide-react" ;
2+ import { useState } from "react" ;
33
44import { type PermissionStatus } from "@hypr/plugin-permissions" ;
55import { Button } from "@hypr/ui/components/ui/button" ;
66import { cn } from "@hypr/utils" ;
77
8- export function useAccessPermission ( config : {
9- queryKey : string ;
10- checkPermission : ( ) => Promise <
11- | { status : "ok" ; data : PermissionStatus }
12- | { status : "error" ; error : string }
13- > ;
14- requestPermission : ( ) => Promise < unknown > ;
15- openSettings : ( ) => Promise < unknown > ;
8+ function ActionLink ( {
9+ onClick ,
10+ disabled ,
11+ children ,
12+ } : {
13+ onClick : ( ) => void ;
14+ disabled ?: boolean ;
15+ children : React . ReactNode ;
1616} ) {
17- const status = useQuery ( {
18- queryKey : [ config . queryKey ] ,
19- queryFn : async ( ) => {
20- const result = await config . checkPermission ( ) ;
21- if ( result . status === "ok" ) {
22- return result . data ;
23- }
24- return "denied" as PermissionStatus ;
25- } ,
26- refetchInterval : 1000 ,
27- } ) ;
28-
29- const requestAccess = useMutation ( {
30- mutationFn : config . requestPermission ,
31- onSuccess : ( ) => {
32- setTimeout ( ( ) => status . refetch ( ) , 1000 ) ;
33- } ,
34- } ) ;
35-
36- const isAuthorized = status . data === "authorized" ;
37- const isPending = requestAccess . isPending ;
38-
39- const handleAction = async ( ) => {
40- if ( isAuthorized ) {
41- await config . openSettings ( ) ;
42- } else if ( status . data === "denied" ) {
43- await config . openSettings ( ) ;
44- } else {
45- requestAccess . mutate ( ) ;
46- }
47- } ;
48-
49- return { status : status . data , isAuthorized, isPending, handleAction } ;
17+ return (
18+ < button
19+ type = "button"
20+ onClick = { onClick }
21+ disabled = { disabled }
22+ className = { cn ( [
23+ "underline hover:text-neutral-900 transition-colors" ,
24+ disabled && "opacity-50 cursor-not-allowed" ,
25+ ] ) }
26+ >
27+ { children }
28+ </ button >
29+ ) ;
5030}
5131
5232export function AccessPermissionRow ( {
5333 title,
54- grantedDescription,
55- requestDescription,
56- isAuthorized,
34+ status,
5735 isPending,
58- onAction,
36+ onOpen,
37+ onRequest,
38+ onReset,
5939} : {
6040 title : string ;
61- grantedDescription : string ;
62- requestDescription : string ;
63- isAuthorized : boolean ;
41+ status : PermissionStatus | undefined ;
6442 isPending : boolean ;
65- onAction : ( ) => void ;
43+ onOpen : ( ) => void ;
44+ onRequest : ( ) => void ;
45+ onReset : ( ) => void ;
6646} ) {
47+ const [ showActions , setShowActions ] = useState ( false ) ;
48+ const isAuthorized = status === "authorized" ;
49+ const isDenied = status === "denied" ;
50+
51+ const handleButtonClick = ( ) => {
52+ if ( isAuthorized || isDenied ) {
53+ onOpen ( ) ;
54+ } else {
55+ onRequest ( ) ;
56+ }
57+ } ;
58+
6759 return (
6860 < div className = "flex items-center justify-between gap-4 py-2" >
6961 < div className = "flex-1" >
@@ -76,14 +68,37 @@ export function AccessPermissionRow({
7668 { ! isAuthorized && < AlertCircleIcon className = "size-4" /> }
7769 < h3 className = "text-sm font-medium" > { title } </ h3 >
7870 </ div >
79- < p className = "text-xs text-neutral-600" >
80- { isAuthorized ? grantedDescription : requestDescription }
81- </ p >
71+ < div className = "text-xs text-neutral-600" >
72+ { ! showActions ? (
73+ < button
74+ type = "button"
75+ onClick = { ( ) => setShowActions ( true ) }
76+ className = "underline hover:text-neutral-900 transition-colors"
77+ >
78+ Having trouble?
79+ </ button >
80+ ) : (
81+ < div >
82+ You can{ " " }
83+ < ActionLink onClick = { onRequest } disabled = { isPending } >
84+ Request,
85+ </ ActionLink > { " " }
86+ < ActionLink onClick = { onReset } disabled = { isPending } >
87+ Reset
88+ </ ActionLink > { " " }
89+ or{ " " }
90+ < ActionLink onClick = { onOpen } disabled = { isPending } >
91+ Open
92+ </ ActionLink > { " " }
93+ permission panel.
94+ </ div >
95+ ) }
96+ </ div >
8297 </ div >
8398 < Button
8499 variant = { isAuthorized ? "outline" : "default" }
85100 size = "icon"
86- onClick = { onAction }
101+ onClick = { handleButtonClick }
87102 disabled = { isPending }
88103 className = { cn ( [
89104 "size-8" ,
0 commit comments