VUE

usePermissions Composable

Reactive browser permission checking with request functionality

Vue3ComposablesPermissionsBrowserReactive

Code

import { ref, watch, onMounted } from 'vue';

type PermissionName = 'camera' | 'microphone' | 'notifications' | 'geolocation' | 'clipboard-read' | 'clipboard-write';
type PermissionStatus = 'granted' | 'denied' | 'prompt' | 'unsupported';

export function usePermissions(permissionName: PermissionName) {
  const status = ref<PermissionStatus>('unsupported');
  const isGranted = ref(false);
  const isDenied = ref(false);
  const isPrompt = ref(false);

  // Update derived states
  const updateDerivedStates = () => {
    isGranted.value = status.value === 'granted';
    isDenied.value = status.value === 'denied';
    isPrompt.value = status.value === 'prompt';
  };

  // Check permission status
  const checkPermission = __TOKEN_52__ () => {
    try {
      __TOKEN_54__ (!navigator.permissions) {
        status.value = 'unsupported';
        updateDerivedStates();
        return;
      }

      const permissionStatus = await navigator.permissions.query({
        name: permissionName as PermissionName
      });

      // Update initial status
      status.value = permissionStatus.state as PermissionStatus;
      updateDerivedStates();

      // Listen for status changes
      permissionStatus.addEventListener('change', () => {
        status.value = permissionStatus.state as PermissionStatus;
        updateDerivedStates();
      });
    } __TOKEN_58__ (error) {
      console.error('Failed to check permission:', error);
      status.value = 'unsupported';
      updateDerivedStates();
    }
  };

  // Request permission (for permissions that require direct request)
  const requestPermission = __TOKEN_60__ (): Promise<boolean> => {
    try {
      switch (permissionName) {
        case 'camera':
          await navigator.mediaDevices.getUserMedia({ video: true });
          break;
        case 'microphone':
          await navigator.mediaDevices.getUserMedia({ audio: true });
          break;
        case 'notifications':
          await Notification.requestPermission();
          break;
        case 'geolocation':
          await new __TOKEN_80__((resolve, reject) => {
            navigator.geolocation.getCurrentPosition(resolve, reject);
          });
          break;
        default:
          break;
      }

      // Re-check status after request
      await checkPermission();
      return isGranted.value;
    } __TOKEN_69__ (error) {
      console.error('Failed to request permission:', error);
      await checkPermission();
      return false;
    }
  };

  // Initial check
  onMounted(() => {
    checkPermission();
  });

  // Watch for status changes
  watch(status, updateDerivedStates);

  return {
    status,
    isGranted,
    isDenied,
    isPrompt,
    checkPermission,
    requestPermission
  };
}

// Usage example
// const { isGranted, requestPermission } = usePermissions('notifications');
// const enableNotifications = async () => {
//   const granted = await requestPermission();
//   if (granted) {
//     new Notification('Notifications enabled!');
//   }
// };