168 lines
6.3 KiB
TypeScript
168 lines
6.3 KiB
TypeScript
"use client";
|
|
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
|
import { CheckSquare } from "lucide-react";
|
|
import { useReportDesigner } from "@/contexts/ReportDesignerContext";
|
|
import type { ComponentConfig } from "@/types/report";
|
|
|
|
interface Props {
|
|
component: ComponentConfig;
|
|
/** 우측 패널: "style" | 모달: "data" | 미전달: 전체 표시 (하위 호환) */
|
|
section?: "style" | "data";
|
|
}
|
|
|
|
export function CheckboxProperties({ component, section }: Props) {
|
|
const { updateComponent, queries, getQueryResult } = useReportDesigner();
|
|
|
|
const showStyle = !section || section === "style";
|
|
const showData = !section || section === "data";
|
|
|
|
return (
|
|
<>
|
|
{/* 체크박스 스타일 — 우측 패널(section="style")에서 표시 */}
|
|
{showStyle && (
|
|
<div className="mt-4 space-y-3 rounded-xl border border-purple-200 bg-purple-50/50 p-4">
|
|
<div className="flex items-center gap-2 text-sm font-semibold text-purple-700">
|
|
<CheckSquare className="h-4 w-4" />
|
|
체크박스 스타일
|
|
</div>
|
|
|
|
{/* 레이블 위치 */}
|
|
<div>
|
|
<Label className="text-xs">레이블 위치</Label>
|
|
<Select
|
|
value={component.checkboxLabelPosition || "right"}
|
|
onValueChange={(value) =>
|
|
updateComponent(component.id, { checkboxLabelPosition: value as "left" | "right" })
|
|
}
|
|
>
|
|
<SelectTrigger className="h-9">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="left">왼쪽</SelectItem>
|
|
<SelectItem value="right">오른쪽</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
{/* 체크박스 크기 */}
|
|
<div>
|
|
<Label className="text-xs">체크박스 크기 (px)</Label>
|
|
<Input
|
|
type="number"
|
|
value={component.checkboxSize || 18}
|
|
onChange={(e) => updateComponent(component.id, { checkboxSize: Number(e.target.value) })}
|
|
min={12}
|
|
max={40}
|
|
className="h-9"
|
|
/>
|
|
</div>
|
|
|
|
{/* 색상 설정 */}
|
|
<div className="grid grid-cols-2 gap-2">
|
|
<div>
|
|
<Label className="text-xs">체크 색상</Label>
|
|
<Input
|
|
type="color"
|
|
value={component.checkboxColor || "#2563eb"}
|
|
onChange={(e) => updateComponent(component.id, { checkboxColor: e.target.value })}
|
|
className="h-9 w-full"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label className="text-xs">테두리 색상</Label>
|
|
<Input
|
|
type="color"
|
|
value={component.checkboxBorderColor || "#6b7280"}
|
|
onChange={(e) => updateComponent(component.id, { checkboxBorderColor: e.target.value })}
|
|
className="h-9 w-full"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 체크박스 데이터 — 모달(section="data")에서 표시 */}
|
|
{showData && (
|
|
<div className="mt-4 space-y-3 rounded-xl border border-purple-200 bg-purple-50/50 p-4">
|
|
<div className="flex items-center gap-2 text-sm font-semibold text-purple-700">
|
|
<CheckSquare className="h-4 w-4" />
|
|
체크박스 데이터
|
|
</div>
|
|
|
|
{/* 체크 상태 (쿼리 연결 없을 때) */}
|
|
{!component.queryId && (
|
|
<div className="flex items-center gap-2">
|
|
<input
|
|
type="checkbox"
|
|
id="checkboxChecked"
|
|
checked={component.checkboxChecked === true}
|
|
onChange={(e) => updateComponent(component.id, { checkboxChecked: e.target.checked })}
|
|
className="h-4 w-4 rounded border-gray-300"
|
|
/>
|
|
<Label htmlFor="checkboxChecked" className="text-xs">
|
|
체크됨
|
|
</Label>
|
|
</div>
|
|
)}
|
|
|
|
{/* 쿼리 연결 시 필드 선택 */}
|
|
{component.queryId && (
|
|
<div>
|
|
<Label className="text-xs">체크 상태 바인딩 필드</Label>
|
|
<Select
|
|
value={component.checkboxFieldName || "none"}
|
|
onValueChange={(value) =>
|
|
updateComponent(component.id, { checkboxFieldName: value === "none" ? "" : value })
|
|
}
|
|
>
|
|
<SelectTrigger className="h-9">
|
|
<SelectValue placeholder="필드 선택" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="none">선택 안함</SelectItem>
|
|
{(() => {
|
|
const query = queries.find((q) => q.id === component.queryId);
|
|
const result = query ? getQueryResult(query.id) : null;
|
|
if (result && result.fields) {
|
|
return result.fields.map((field: string) => (
|
|
<SelectItem key={field} value={field}>
|
|
{field}
|
|
</SelectItem>
|
|
));
|
|
}
|
|
return null;
|
|
})()}
|
|
</SelectContent>
|
|
</Select>
|
|
<p className="mt-1 text-[10px] text-gray-500">true, "Y", 1 등 truthy 값이면 체크됨</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* 레이블 텍스트 */}
|
|
<div>
|
|
<Label className="text-xs">레이블 텍스트</Label>
|
|
<Input
|
|
type="text"
|
|
value={component.checkboxLabel || ""}
|
|
onChange={(e) => updateComponent(component.id, { checkboxLabel: e.target.value })}
|
|
placeholder="체크박스 옆 텍스트"
|
|
className="h-9"
|
|
/>
|
|
</div>
|
|
|
|
{/* 쿼리 연결 안내 */}
|
|
{!component.queryId && (
|
|
<div className="rounded border border-purple-200 bg-purple-100 p-2 text-xs text-purple-800">
|
|
쿼리를 연결하면 데이터베이스 값으로 체크 상태를 결정할 수 있습니다.
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|