Added Phase‑1 continuation work across deep links, offline moderation queue, and admin push.
resources/js/admin/mobile/lib.
- Admin push is end‑to‑end: new backend model/migration/service/job + API endpoints, admin runtime config, push‑aware
service worker, and a settings toggle via useAdminPushSubscription. Notifications now auto‑refresh on push.
- New PHP/JS tests: admin push API feature test and queue/haptics unit tests
Added admin-specific PWA icon assets and wired them into the admin manifest, service worker, and admin shell, plus a
new “Device & permissions” card in mobile Settings with a persistent storage action and translations.
Details: public/manifest.json, public/admin-sw.js, resources/views/admin.blade.php, new icons in public/; new hook
resources/js/admin/mobile/hooks/useDevicePermissions.ts, helpers/tests in resources/js/admin/mobile/lib/
devicePermissions.ts + resources/js/admin/mobile/lib/devicePermissions.test.ts, and Settings UI updates in resources/
js/admin/mobile/SettingsPage.tsx with copy in resources/js/admin/i18n/locales/en/management.json and resources/js/
admin/i18n/locales/de/management.json.
This commit is contained in:
97
resources/js/admin/mobile/hooks/useDevicePermissions.ts
Normal file
97
resources/js/admin/mobile/hooks/useDevicePermissions.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
normalizePermissionState,
|
||||
resolveStorageStatus,
|
||||
type PermissionStatus,
|
||||
type StorageStatus,
|
||||
} from '../lib/devicePermissions';
|
||||
|
||||
type DevicePermissionsState = {
|
||||
notifications: PermissionStatus;
|
||||
camera: PermissionStatus;
|
||||
storage: StorageStatus;
|
||||
};
|
||||
|
||||
type DevicePermissionsHook = DevicePermissionsState & {
|
||||
loading: boolean;
|
||||
refresh: () => Promise<void>;
|
||||
requestPersistentStorage: () => Promise<boolean>;
|
||||
};
|
||||
|
||||
export function useDevicePermissions(): DevicePermissionsHook {
|
||||
const [permissions, setPermissions] = React.useState<DevicePermissionsState>({
|
||||
notifications: 'unsupported',
|
||||
camera: 'unsupported',
|
||||
storage: 'unsupported',
|
||||
});
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
|
||||
const refresh = React.useCallback(async () => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
let notificationState: PermissionStatus = 'unsupported';
|
||||
if ('Notification' in window) {
|
||||
notificationState = normalizePermissionState(Notification.permission);
|
||||
}
|
||||
|
||||
let cameraState: PermissionStatus = 'unsupported';
|
||||
if (navigator.permissions?.query) {
|
||||
try {
|
||||
const cameraPermission = await navigator.permissions.query({
|
||||
name: 'camera' as PermissionName,
|
||||
});
|
||||
cameraState = normalizePermissionState(cameraPermission.state);
|
||||
} catch {
|
||||
cameraState = 'unsupported';
|
||||
}
|
||||
}
|
||||
|
||||
const storageSupported = Boolean(navigator.storage?.persisted);
|
||||
let persisted: boolean | null = null;
|
||||
if (storageSupported) {
|
||||
persisted = await navigator.storage.persisted();
|
||||
}
|
||||
|
||||
setPermissions({
|
||||
notifications: notificationState,
|
||||
camera: cameraState,
|
||||
storage: resolveStorageStatus(persisted, storageSupported),
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const requestPersistentStorage = React.useCallback(async () => {
|
||||
if (typeof navigator === 'undefined' || !navigator.storage?.persist) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const granted = await navigator.storage.persist();
|
||||
setPermissions((prev) => ({
|
||||
...prev,
|
||||
storage: granted ? 'persisted' : 'available',
|
||||
}));
|
||||
return granted;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
void refresh();
|
||||
}, [refresh]);
|
||||
|
||||
return {
|
||||
...permissions,
|
||||
loading,
|
||||
refresh,
|
||||
requestPersistentStorage,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user