tenantpilot/lib/hooks/useCopyToClipboard.ts
Ahmed Darrazi aa598452e9
All checks were successful
Trigger Cloudarix Deploy / call-webhook (push) Successful in 2s
feat(policy-explorer-v2): Phase 6 - Enhanced Detail View
Implemented Tasks T038-T046:
- T038: Created useCopyToClipboard hook with toast notifications
- T039: Skipped (unit tests - optional)
- T040: Added copy button for Policy ID field
- T041: Added copy button for Setting Name field
- T042: Added tabs for Details and Raw JSON views
- T043: Implemented Raw JSON tab with syntax highlighting
- T044: Created getIntunePortalLink utility (8 policy types)
- T045: Added Open in Intune button with URL construction
- T046: Fallback to copy Policy ID if URL unavailable

Files Created:
- lib/hooks/useCopyToClipboard.ts (65 lines)
- lib/utils/policy-table-helpers.ts (127 lines)

Files Updated:
- components/policy-explorer/PolicyDetailSheet.tsx (enhanced with tabs, copy buttons, Intune links)

Features:
- Copy-to-clipboard for all fields with visual feedback
- Two-tab interface: Details (enhanced fields) and Raw JSON (full object)
- Deep linking to Intune portal by policy type
- Clipboard API with document.execCommand fallback
- Toast notifications for user feedback
2025-12-10 00:40:09 +01:00

71 lines
2.0 KiB
TypeScript

/**
* useCopyToClipboard Hook
*
* Wrapper for Clipboard API with success/error handling and toast notifications.
*
* Features:
* - Copy text to clipboard
* - Success/error state tracking
* - Automatic toast notifications
* - Fallback for older browsers
*/
import { useState } from 'react';
import { toast } from 'sonner';
interface CopyToClipboardResult {
copy: (text: string, successMessage?: string) => Promise<void>;
isCopied: boolean;
error: Error | null;
}
export function useCopyToClipboard(): CopyToClipboardResult {
const [isCopied, setIsCopied] = useState(false);
const [error, setError] = useState<Error | null>(null);
const copy = async (text: string, successMessage: string = 'Copied to clipboard') => {
// Reset state
setIsCopied(false);
setError(null);
try {
// Modern Clipboard API
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(text);
} else {
// Fallback for older browsers or non-secure contexts
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
const successful = document.execCommand('copy');
textArea.remove();
if (!successful) {
throw new Error('Copy command failed');
}
}
setIsCopied(true);
toast.success(successMessage);
// Reset isCopied after 2 seconds
setTimeout(() => {
setIsCopied(false);
}, 2000);
} catch (err) {
const copyError = err instanceof Error ? err : new Error('Failed to copy');
setError(copyError);
toast.error('Failed to copy to clipboard');
console.error('Copy error:', copyError);
}
};
return { copy, isCopied, error };
}