pmtool / src /components /asset-request /AcknowledgeDialog.tsx
devarshia5's picture
Upload 487 files
d97b8f9 verified
Raw
History Blame Contribute Delete
6.43 kB
import React, { useState, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import { Textarea } from '@/components/ui/textarea';
import { CheckCircle, Loader2, AlertCircle } from 'lucide-react';
import { ASSET_REQUEST_CONFIG } from '@/types/asset-request';
interface AcknowledgeDialogProps {
isOpen: boolean;
onClose: () => void;
onConfirm: (comments: string) => Promise<void>;
requestId: number;
employeeName: string;
}
const AcknowledgeDialog: React.FC<AcknowledgeDialogProps> = ({
isOpen,
onClose,
onConfirm,
requestId,
employeeName,
}) => {
const [comments, setComments] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState('');
// Reset state when dialog opens
useEffect(() => {
if (isOpen) {
setComments('');
setError('');
setIsSubmitting(false);
}
}, [isOpen]);
// Handle escape key and body scroll
useEffect(() => {
if (!isOpen) return;
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape' && !isSubmitting) {
onClose();
}
};
document.addEventListener('keydown', handleEscape);
document.body.style.overflow = 'hidden';
return () => {
document.removeEventListener('keydown', handleEscape);
document.body.style.overflow = 'unset';
};
}, [isOpen, isSubmitting, onClose]);
const handleSubmit = async () => {
setError('');
setIsSubmitting(true);
try {
await onConfirm(comments.trim());
onClose();
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred');
} finally {
setIsSubmitting(false);
}
};
const handleOverlayClick = (e: React.MouseEvent) => {
if (!isSubmitting && e.target === e.currentTarget) {
onClose();
}
};
if (!isOpen) return null;
return (
<div
className="fixed inset-0 z-[999] flex items-center justify-center p-4 overflow-y-auto"
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
>
{/* Overlay */}
<div
className="fixed inset-0 bg-black/80 backdrop-blur-sm transition-opacity"
onClick={handleOverlayClick}
aria-hidden="true"
/>
{/* Modal Content */}
<div
className="relative z-[1000] w-full max-w-md rounded-lg border bg-background shadow-lg animate-in fade-in-0 zoom-in-95 duration-200"
onClick={(e) => e.stopPropagation()}
>
{/* Header */}
<div className="flex items-start gap-3 p-6 border-b">
<div className="p-2 rounded-full flex-shrink-0 bg-purple-100">
<CheckCircle className="h-5 w-5 text-purple-600" />
</div>
<div className="flex-1 min-w-0">
<h2
id="dialog-title"
className="text-lg font-semibold text-foreground"
>
Acknowledge Asset Receipt
</h2>
<p className="text-sm text-muted-foreground mt-1">
Confirm that you have received the assigned assets for request #{requestId}
</p>
</div>
</div>
{/* Content */}
<div className="p-6 space-y-4">
{/* Request Info */}
<div className="bg-muted rounded-md p-3 text-sm space-y-1">
<div className="flex justify-between">
<span className="text-muted-foreground">Request ID:</span>
<span className="font-medium">#{requestId}</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground">Employee:</span>
<span className="font-medium">{employeeName}</span>
</div>
</div>
{/* Comments Input (Optional) */}
<div>
<label htmlFor="comments" className="text-sm font-medium mb-2 block">
Comments (Optional)
</label>
<Textarea
id="comments"
placeholder="Add any comments about the received assets (optional)..."
value={comments}
onChange={(e) => {
setComments(e.target.value);
setError('');
}}
maxLength={ASSET_REQUEST_CONFIG.MAX_ADMIN_COMMENTS_LENGTH}
rows={3}
className="resize-none w-full"
disabled={isSubmitting}
autoFocus
/>
<div className="flex justify-between items-center mt-1">
<div className="text-xs text-muted-foreground">
{comments.length}/{ASSET_REQUEST_CONFIG.MAX_ADMIN_COMMENTS_LENGTH} characters
</div>
{error && (
<div className="flex items-center gap-1 text-xs text-destructive">
<AlertCircle className="h-3 w-3" />
{error}
</div>
)}
</div>
</div>
{/* Info Message */}
<div className="bg-blue-50 border border-blue-200 rounded-md p-3 text-sm text-blue-800">
<p>By acknowledging, you confirm that you have received all assigned assets in good condition.</p>
</div>
{/* Action Buttons */}
<div className="flex justify-end gap-3 pt-2">
<Button
type="button"
variant="outline"
onClick={onClose}
disabled={isSubmitting}
>
Cancel
</Button>
<Button
type="button"
onClick={handleSubmit}
disabled={isSubmitting}
className="bg-purple-600 hover:bg-purple-700 text-white"
>
{isSubmitting ? (
<>
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
Acknowledging...
</>
) : (
<>
<CheckCircle className="h-4 w-4 mr-2" />
Acknowledge Receipt
</>
)}
</Button>
</div>
</div>
</div>
</div>
);
};
export default AcknowledgeDialog;