173 lines
5.6 KiB
TypeScript
173 lines
5.6 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useRef } from 'react';
|
||
|
|
import { Mic, Upload } from 'lucide-react';
|
||
|
|
import { Input } from '@/components/ui/input';
|
||
|
|
import { Label } from '@/components/ui/label';
|
||
|
|
import { Button } from '@/components/ui/button';
|
||
|
|
import { Textarea } from '@/components/ui/textarea';
|
||
|
|
import type { ProposalData } from './types';
|
||
|
|
|
||
|
|
interface ProposalFormProps {
|
||
|
|
data: ProposalData;
|
||
|
|
onChange: (data: ProposalData) => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function ProposalForm({ data, onChange }: ProposalFormProps) {
|
||
|
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||
|
|
|
||
|
|
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||
|
|
const files = e.target.files;
|
||
|
|
if (files) {
|
||
|
|
onChange({ ...data, attachments: [...data.attachments, ...Array.from(files)] });
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="space-y-6">
|
||
|
|
{/* 구매처 정보 */}
|
||
|
|
<div className="bg-white rounded-lg border p-6">
|
||
|
|
<h3 className="text-lg font-semibold mb-4">구매처 정보</h3>
|
||
|
|
|
||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label htmlFor="vendor">구매처</Label>
|
||
|
|
<Input
|
||
|
|
id="vendor"
|
||
|
|
placeholder="구매처를 입력해주세요"
|
||
|
|
value={data.vendor}
|
||
|
|
onChange={(e) => onChange({ ...data, vendor: e.target.value })}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label htmlFor="vendorPaymentDate">구매처 결제일</Label>
|
||
|
|
<Input
|
||
|
|
id="vendorPaymentDate"
|
||
|
|
type="date"
|
||
|
|
value={data.vendorPaymentDate}
|
||
|
|
onChange={(e) => onChange({ ...data, vendorPaymentDate: e.target.value })}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 품의서 정보 */}
|
||
|
|
<div className="bg-white rounded-lg border p-6">
|
||
|
|
<h3 className="text-lg font-semibold mb-4">품의서 정보</h3>
|
||
|
|
|
||
|
|
<div className="space-y-4">
|
||
|
|
{/* 제목 */}
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label htmlFor="title">제목</Label>
|
||
|
|
<Input
|
||
|
|
id="title"
|
||
|
|
placeholder="제목을 입력해주세요"
|
||
|
|
value={data.title}
|
||
|
|
onChange={(e) => onChange({ ...data, title: e.target.value })}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 품의 내역 */}
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label htmlFor="description">품의 내역</Label>
|
||
|
|
<div className="relative">
|
||
|
|
<Textarea
|
||
|
|
id="description"
|
||
|
|
placeholder="품의 내역을 입력해주세요"
|
||
|
|
value={data.description}
|
||
|
|
onChange={(e) => onChange({ ...data, description: e.target.value })}
|
||
|
|
className="min-h-[100px] pr-12"
|
||
|
|
/>
|
||
|
|
<Button
|
||
|
|
type="button"
|
||
|
|
variant="outline"
|
||
|
|
size="sm"
|
||
|
|
className="absolute right-2 bottom-2"
|
||
|
|
title="녹음"
|
||
|
|
>
|
||
|
|
<Mic className="w-4 h-4" />
|
||
|
|
녹음
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 품의 사유 */}
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label htmlFor="reason">품의 사유</Label>
|
||
|
|
<div className="relative">
|
||
|
|
<Textarea
|
||
|
|
id="reason"
|
||
|
|
placeholder="품의 사유를 입력해주세요"
|
||
|
|
value={data.reason}
|
||
|
|
onChange={(e) => onChange({ ...data, reason: e.target.value })}
|
||
|
|
className="min-h-[100px] pr-12"
|
||
|
|
/>
|
||
|
|
<Button
|
||
|
|
type="button"
|
||
|
|
variant="outline"
|
||
|
|
size="sm"
|
||
|
|
className="absolute right-2 bottom-2"
|
||
|
|
title="녹음"
|
||
|
|
>
|
||
|
|
<Mic className="w-4 h-4" />
|
||
|
|
녹음
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 예상 비용 */}
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label htmlFor="estimatedCost">예상 비용</Label>
|
||
|
|
<Input
|
||
|
|
id="estimatedCost"
|
||
|
|
type="number"
|
||
|
|
placeholder="금액을 입력해주세요"
|
||
|
|
value={data.estimatedCost || ''}
|
||
|
|
onChange={(e) => onChange({ ...data, estimatedCost: Number(e.target.value) || 0 })}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 참고 이미지 정보 */}
|
||
|
|
<div className="bg-white rounded-lg border p-6">
|
||
|
|
<h3 className="text-lg font-semibold mb-4">참고 이미지 정보</h3>
|
||
|
|
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label>첨부파일</Label>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Input
|
||
|
|
type="text"
|
||
|
|
readOnly
|
||
|
|
placeholder="파일을 선택해주세요"
|
||
|
|
value={data.attachments.map((f) => f.name).join(', ')}
|
||
|
|
className="flex-1"
|
||
|
|
/>
|
||
|
|
<input
|
||
|
|
ref={fileInputRef}
|
||
|
|
type="file"
|
||
|
|
multiple
|
||
|
|
className="hidden"
|
||
|
|
onChange={handleFileChange}
|
||
|
|
accept="image/*"
|
||
|
|
/>
|
||
|
|
<Button
|
||
|
|
type="button"
|
||
|
|
variant="outline"
|
||
|
|
onClick={() => fileInputRef.current?.click()}
|
||
|
|
>
|
||
|
|
<Upload className="w-4 h-4 mr-2" />
|
||
|
|
찾기
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
{data.attachments.length > 0 && (
|
||
|
|
<div className="text-sm text-gray-500">
|
||
|
|
{data.attachments.length}개 파일 선택됨
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|