Re_Figma_Code/src/components/workflow/CreateRequest/BasicInformationStep.tsx

229 lines
11 KiB
TypeScript

import { motion } from 'framer-motion';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { RichTextEditor } from '@/components/ui/rich-text-editor';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { Badge } from '@/components/ui/badge';
import { FileText, Zap, Clock } from 'lucide-react';
import { FormData, RequestTemplate } from '@/hooks/useCreateRequestForm';
interface BasicInformationStepProps {
formData: FormData;
selectedTemplate: RequestTemplate | null;
updateFormData: (field: keyof FormData, value: any) => void;
}
/**
* Component: BasicInformationStep
*
* Purpose: Step 2 - Basic information form (title, description, priority)
*
* Features:
* - Request title and description inputs
* - Priority selection (Express/Standard)
* - Template-specific additional fields
* - Test IDs for testing
*/
export function BasicInformationStep({
formData,
selectedTemplate,
updateFormData
}: BasicInformationStepProps) {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
className="space-y-6"
data-testid="basic-information-step"
>
<div className="text-center mb-8" data-testid="basic-information-header">
<div className="w-16 h-16 bg-gradient-to-br from-green-500 to-blue-600 rounded-2xl flex items-center justify-center mx-auto mb-4">
<FileText className="w-8 h-8 text-white" />
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2" data-testid="basic-information-title">
Basic Information
</h2>
<p className="text-gray-600" data-testid="basic-information-description">
Provide the essential details for your {selectedTemplate?.name || 'request'}.
</p>
</div>
<div className="max-w-2xl mx-auto space-y-6" data-testid="basic-information-form">
<div data-testid="basic-information-title-field">
<Label htmlFor="title" className="text-base font-semibold">Request Title *</Label>
<p className="text-sm text-gray-600 mb-3">
Be specific and descriptive. This will be visible to all participants.
</p>
<Input
id="title"
placeholder="e.g., Approval on new office location"
value={formData.title}
onChange={(e) => updateFormData('title', e.target.value)}
className="text-base h-12 border-2 border-gray-300 focus:border-blue-500 bg-white shadow-sm"
data-testid="basic-information-title-input"
/>
</div>
<div data-testid="basic-information-description-field">
<Label htmlFor="description" className="text-base font-semibold">Detailed Description *</Label>
<p className="text-sm text-gray-600 mb-3">
Explain what you need approval for, why it's needed, and any relevant background information.
<span className="block mt-1 text-xs text-blue-600">
💡 Tip: You can paste formatted content (lists, tables) and the formatting will be preserved.
</span>
</p>
<RichTextEditor
value={formData.description || ''}
onChange={(html) => updateFormData('description', html)}
placeholder="Provide comprehensive details about your request including scope, objectives, expected outcomes, and any supporting context that will help approvers make an informed decision."
className="min-h-[120px] text-base border-2 border-gray-300 focus-within:border-blue-500 bg-white shadow-sm"
minHeight="120px"
data-testid="basic-information-description-textarea"
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6" data-testid="basic-information-priority-section">
<div data-testid="basic-information-priority-field">
<Label className="text-base font-semibold">Priority Level *</Label>
<p className="text-sm text-gray-600 mb-2">
select priority for your request
</p>
<RadioGroup
value={formData.priority || ''}
onValueChange={(value) => updateFormData('priority', value)}
data-testid="basic-information-priority-radio-group"
>
<div
className={`flex items-center space-x-3 p-3 rounded-lg border-2 cursor-pointer transition-all ${
formData.priority === 'express'
? 'border-red-500 bg-red-100'
: 'border-red-200 bg-red-50 hover:bg-red-100'
}`}
onClick={() => updateFormData('priority', 'express')}
data-testid="basic-information-priority-express-option"
>
<RadioGroupItem value="express" id="express" />
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<Zap className="w-4 h-4 text-red-600" />
<Label htmlFor="express" className="font-medium text-red-900 cursor-pointer">Express</Label>
<Badge variant="destructive" className="text-xs">URGENT</Badge>
</div>
<p className="text-xs text-red-700">
Includes calendar days in TAT - faster processing timeline
</p>
</div>
</div>
<div
className={`flex items-center space-x-3 p-3 rounded-lg border cursor-pointer transition-all ${
formData.priority === 'standard'
? 'border-blue-500 bg-blue-50'
: 'border-gray-200 hover:bg-gray-50'
}`}
onClick={() => updateFormData('priority', 'standard')}
data-testid="basic-information-priority-standard-option"
>
<RadioGroupItem value="standard" id="standard" />
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<Clock className="w-4 h-4 text-blue-600" />
<Label htmlFor="standard" className="font-medium text-blue-900 cursor-pointer">Standard</Label>
<Badge variant="secondary" className="text-xs">DEFAULT</Badge>
</div>
<p className="text-xs text-gray-600">
Includes working days in TAT - regular processing timeline
</p>
</div>
</div>
</RadioGroup>
</div>
</div>
{/* Template-specific fields */}
{(selectedTemplate?.fields.amount || selectedTemplate?.fields.vendor || selectedTemplate?.fields.timeline || selectedTemplate?.fields.impact) && (
<div className="border-t pt-6" data-testid="basic-information-additional-details">
<h3 className="text-lg font-semibold text-gray-900 mb-4">Additional Details</h3>
<div className="space-y-6">
{selectedTemplate?.fields.amount && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4" data-testid="basic-information-amount-field">
<div className="md:col-span-2">
<Label htmlFor="amount" className="text-base font-semibold">Budget Amount</Label>
<Input
id="amount"
placeholder="Enter amount"
value={formData.amount}
onChange={(e) => updateFormData('amount', e.target.value)}
className="text-base h-12 border-2 border-gray-300 focus:border-blue-500 bg-white shadow-sm"
data-testid="basic-information-amount-input"
/>
</div>
<div>
<Label className="text-base font-semibold">Currency</Label>
<Select
value={formData.currency}
onValueChange={(value) => updateFormData('currency', value)}
data-testid="basic-information-currency-select"
>
<SelectTrigger className="h-12 border-2 border-gray-300 focus:border-blue-500 bg-white shadow-sm">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="USD">USD ($)</SelectItem>
<SelectItem value="EUR">EUR (€)</SelectItem>
<SelectItem value="GBP">GBP (£)</SelectItem>
<SelectItem value="INR">INR (₹)</SelectItem>
</SelectContent>
</Select>
</div>
</div>
)}
{selectedTemplate?.fields.vendor && (
<div data-testid="basic-information-vendor-field">
<Label htmlFor="vendor" className="text-base font-semibold">Vendor/Supplier</Label>
<Input
id="vendor"
placeholder="Enter vendor or supplier name"
value={formData.vendor}
onChange={(e) => updateFormData('vendor', e.target.value)}
className="text-base h-12 border-2 border-gray-300 focus:border-blue-500 bg-white shadow-sm"
data-testid="basic-information-vendor-input"
/>
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div data-testid="basic-information-cost-center-field">
<Label htmlFor="costCenter" className="text-base font-semibold">Cost Center</Label>
<Input
id="costCenter"
placeholder="e.g., Marketing, IT, Operations"
value={formData.costCenter}
onChange={(e) => updateFormData('costCenter', e.target.value)}
className="text-base h-12 border-2 border-gray-300 focus:border-blue-500 bg-white shadow-sm"
data-testid="basic-information-cost-center-input"
/>
</div>
<div data-testid="basic-information-project-field">
<Label htmlFor="project" className="text-base font-semibold">Related Project</Label>
<Input
id="project"
placeholder="Associated project name or code"
value={formData.project}
onChange={(e) => updateFormData('project', e.target.value)}
className="text-base h-12 border-2 border-gray-300 focus:border-blue-500 bg-white shadow-sm"
data-testid="basic-information-project-input"
/>
</div>
</div>
</div>
</div>
)}
</div>
</motion.div>
);
}