Last active
August 2, 2022 13:15
-
-
Save honungsburk/f5897178af325141c00eef1216bb402f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect, useState } from "react"; | |
//////////////////////////////////////////////////////////////////////////////// | |
// Permissions | |
//////////////////////////////////////////////////////////////////////////////// | |
/** | |
* microphone and camera doesn't exist on all browsers! | |
*/ | |
type AllPermissionName = "microphone" | "camera" | PermissionName; | |
type Permissions<Names extends AllPermissionName[]> = { | |
[key in Names[number]]: PermissionState; | |
}; | |
function initPermissions<Names extends AllPermissionName[]>( | |
names: Names | |
): Permissions<Names> { | |
const obj: any = {}; | |
for (let name of names) { | |
obj[name] = "prompt"; | |
} | |
return obj as Permissions<Names>; | |
} | |
/** | |
* Keep track of all granted browser permissions. Automatically updates. | |
* | |
* NOTE: the "microphone" and "camera" permissions are not supported by all browsers! | |
*/ | |
export default function useBrowserPermissions< | |
Names extends AllPermissionName[] | |
>(...permissionNames: Names): Permissions<Names> { | |
const [permissions, setPermissions] = useState<Permissions<Names>>( | |
initPermissions(permissionNames) | |
); | |
useEffect(() => { | |
const unsubs: (() => void)[] = []; | |
const exec = async () => { | |
let localPermissions: any = initPermissions(permissionNames); | |
for (let permissionName of permissionNames) { | |
const permissionStatus = await navigator.permissions.query({ | |
name: permissionName as PermissionName, | |
}); | |
localPermissions[permissionName] = permissionStatus.state; | |
setPermissions({ ...localPermissions }); | |
const listener: (this: PermissionStatus) => void = function () { | |
console.log(permissionName, ":", this.state); | |
if (localPermissions[permissionName] !== this.state) { | |
localPermissions[permissionName] = this.state; | |
setPermissions({ ...localPermissions }); | |
} | |
}; | |
permissionStatus.addEventListener("change", listener); | |
unsubs.push(() => | |
permissionStatus.removeEventListener("change", listener) | |
); | |
} | |
}; | |
exec(); | |
return () => { | |
unsubs.forEach((fn) => fn()); | |
}; | |
}, permissionNames); | |
// IMPORTANT: do not wrapp permissionNames in a list [permissionNames] that will trigger | |
// effect on each render! | |
// This happens because the list is a new refrence each time, but by not wrapping it will look at the values | |
// which are strings and are refer to the same ref each time! | |
return permissions; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment