112 lines
3.4 KiB
TypeScript
112 lines
3.4 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { X, Settings } from 'lucide-react';
|
|
import { getMetaFields } from '@/lib/api/meta';
|
|
import { getUserOverride, upsertUserOverride } from '@/lib/api/override';
|
|
import { FieldConfig } from '@/types/invyone-component';
|
|
|
|
interface CardSettingsPanelProps {
|
|
cardId: string;
|
|
tableName: string;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export function CardSettingsPanel({ cardId, tableName, onClose }: CardSettingsPanelProps) {
|
|
const [fields, setFields] = useState<FieldConfig[]>([]);
|
|
const [overrides, setOverrides] = useState<Record<string, any>>({});
|
|
const [saving, setSaving] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const load = async () => {
|
|
try {
|
|
const [meta, ovr] = await Promise.all([
|
|
getMetaFields(tableName),
|
|
getUserOverride(cardId),
|
|
]);
|
|
if (meta?.fields) setFields(meta.fields.filter((f: FieldConfig) => !f.system));
|
|
if (ovr?.overrides) setOverrides(ovr.overrides);
|
|
} catch (err) {
|
|
console.error('[CardSettings] Load failed:', err);
|
|
}
|
|
};
|
|
load();
|
|
}, [cardId, tableName]);
|
|
|
|
const isFieldHidden = (column: string) => {
|
|
return overrides?.fields?.[column]?.visible === false;
|
|
};
|
|
|
|
const toggleField = async (column: string) => {
|
|
const currentlyHidden = isFieldHidden(column);
|
|
const newOverrides = {
|
|
...overrides,
|
|
fields: {
|
|
...(overrides.fields ?? {}),
|
|
[column]: { ...(overrides.fields?.[column] ?? {}), visible: currentlyHidden },
|
|
},
|
|
};
|
|
|
|
// visible: true 이면 삭제 (기본값이니까)
|
|
if (currentlyHidden) {
|
|
delete newOverrides.fields[column].visible;
|
|
if (Object.keys(newOverrides.fields[column]).length === 0) {
|
|
delete newOverrides.fields[column];
|
|
}
|
|
}
|
|
|
|
setOverrides(newOverrides);
|
|
|
|
setSaving(true);
|
|
try {
|
|
await upsertUserOverride({ card_id: cardId, overrides: newOverrides });
|
|
} catch (err) {
|
|
console.error('[CardSettings] Save failed:', err);
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="dash-settings">
|
|
<div className="dash-settings-head">
|
|
<div className="dash-settings-title">
|
|
<Settings size={13} />
|
|
<span>카드 설정</span>
|
|
</div>
|
|
<button
|
|
className="dash-card-btn"
|
|
onClick={onClose}
|
|
style={{ width: 22, height: 22, borderRadius: 6 }}
|
|
>
|
|
<X size={14} />
|
|
</button>
|
|
</div>
|
|
<div className="dash-settings-body">
|
|
<div style={{
|
|
fontSize: '.55rem', fontWeight: 700, color: 'var(--v5-primary)',
|
|
textTransform: 'uppercase', letterSpacing: '.08em',
|
|
padding: '.3rem 0', borderBottom: '1px solid var(--v5-border-subtle)',
|
|
marginBottom: '.4rem',
|
|
}}>
|
|
컬럼 표시/숨김
|
|
</div>
|
|
{fields.map((f) => (
|
|
<div key={f.column} className="dash-settings-row">
|
|
<span className="dash-settings-label">{f.label}</span>
|
|
<div
|
|
className={`dash-toggle${!isFieldHidden(f.column) ? ' on' : ''}`}
|
|
onClick={() => toggleField(f.column)}
|
|
/>
|
|
</div>
|
|
))}
|
|
{saving && (
|
|
<div style={{ textAlign: 'center', fontSize: '.6rem', color: 'var(--v5-text-muted)', marginTop: '.5rem' }}>
|
|
저장 중...
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|