Files
tautkan-kanban/client/src/components/ColumnSettingsModal.tsx
T
Power BI Dev 88c7c653c2 first init
2026-08-17 10:52:09 +07:00

141 lines
6.4 KiB
TypeScript

import React, { useState } from 'react';
import { Settings2, X, AlertTriangle, Clock } from 'lucide-react';
import { Column } from '../types/index.js';
import { soundFx } from '../utils/sound.js';
import { useTranslation } from '../utils/i18n.js';
interface ColumnSettingsModalProps {
column: Column;
onClose: () => void;
onSave: (columnId: string, updates: { title: string; maxWipLimit: number; autoStaleHours: number }) => void;
}
export const ColumnSettingsModal: React.FC<ColumnSettingsModalProps> = ({ column, onClose, onSave }) => {
const { t } = useTranslation();
const [title, setTitle] = useState(column.title);
const [maxWipLimit, setMaxWipLimit] = useState<number>(column.maxWipLimit || 0);
const [autoStaleHours, setAutoStaleHours] = useState<number>(column.autoStaleHours || 0);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
soundFx.playClick();
onSave(column.id, {
title: title.trim() || column.title,
maxWipLimit: Number(maxWipLimit) || 0,
autoStaleHours: Number(autoStaleHours) || 0,
});
onClose();
};
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-3 sm:p-4 bg-slate-950/70 backdrop-blur-md animate-fade-in">
<div className="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl shadow-2xl max-w-md w-full p-4 sm:p-6 relative text-slate-900 dark:text-slate-100 max-h-[92vh] overflow-y-auto">
<button
onClick={() => {
soundFx.playClick();
onClose();
}}
className="absolute top-4 right-4 text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 p-1 rounded-md"
>
<X size={18} />
</button>
<div className="flex items-center gap-3 mb-4 sm:mb-5">
<div className="w-9 h-9 sm:w-10 sm:h-10 bg-indigo-50 dark:bg-emerald-500/10 border border-indigo-200 dark:border-emerald-500/30 rounded-xl flex items-center justify-center text-indigo-600 dark:text-emerald-400">
<Settings2 size={18} />
</div>
<div>
<h2 className="text-sm sm:text-base font-bold text-slate-900 dark:text-slate-100">
{t('editColSettings')}
</h2>
<p className="text-xs text-slate-500 dark:text-slate-400 truncate max-w-[200px]">
{column.title}
</p>
</div>
</div>
<form onSubmit={handleSubmit} className="space-y-3.5 text-xs">
{/* Column Title */}
<div>
<label className="block text-xs font-semibold text-slate-700 dark:text-slate-300 mb-1.5">
{t('taskTitle')}
</label>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
className="w-full bg-slate-50 dark:bg-slate-950/70 border border-slate-300 dark:border-slate-800 rounded-lg p-2.5 text-slate-900 dark:text-slate-100 text-xs outline-none focus:border-indigo-500"
required
/>
</div>
{/* WIP Limit Setting */}
<div className="bg-amber-50/70 dark:bg-slate-950/70 border border-amber-200 dark:border-amber-500/30 p-3.5 rounded-xl">
<label className="flex items-center gap-1.5 text-xs font-semibold text-amber-800 dark:text-amber-400 mb-1">
<AlertTriangle size={14} className="text-amber-600 dark:text-amber-400 shrink-0" />
<span>{t('wipLimitLabel')}</span>
</label>
<p className="text-[11px] text-slate-600 dark:text-slate-400 mb-2 leading-relaxed">
Membatasi jumlah kartu aktif di kolom ini agar tim fokus menyelesaikan tugas sebelum mengambil yang baru.
</p>
<div className="flex items-center gap-2">
<input
type="number"
min={0}
max={50}
value={maxWipLimit}
onChange={(e) => setMaxWipLimit(parseInt(e.target.value, 10) || 0)}
className="w-20 sm:w-24 bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-800 rounded-lg p-2 text-slate-900 dark:text-slate-100 text-xs text-center outline-none"
/>
<span className="text-[11px] sm:text-xs text-amber-800 dark:text-amber-300 font-medium">
{maxWipLimit === 0 ? `(${t('wipUnlimited')})` : `(Maks. ${maxWipLimit} kartu)`}
</span>
</div>
</div>
{/* Auto-Stale Hours Setting */}
<div className="bg-cyan-50/70 dark:bg-slate-950/70 border border-cyan-200 dark:border-cyan-500/30 p-3.5 rounded-xl">
<label className="flex items-center gap-1.5 text-xs font-semibold text-cyan-800 dark:text-cyan-400 mb-1">
<Clock size={14} className="text-cyan-600 dark:text-cyan-400 shrink-0" />
<span>{t('autoStaleHoursLabel')}</span>
</label>
<p className="text-[11px] text-slate-600 dark:text-slate-400 mb-2 leading-relaxed">
Memberikan tanda peringatan jika kartu tidak bergerak di kolom ini melebihi durasi yang ditentukan.
</p>
<div className="flex items-center gap-2">
<select
value={autoStaleHours}
onChange={(e) => setAutoStaleHours(parseInt(e.target.value, 10) || 0)}
className="bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-800 rounded-lg p-2 text-slate-900 dark:text-slate-100 text-xs outline-none flex-1"
>
<option value={0}>🚫 Nonaktif (0 Jam)</option>
<option value={12}> 12 Jam</option>
<option value={24}> 24 Jam (1 Hari) [Standar]</option>
<option value={48}> 48 Jam (2 Hari)</option>
<option value={72}> 72 Jam (3 Hari)</option>
<option value={168}> 7 Hari</option>
</select>
</div>
</div>
<div className="flex justify-end gap-2 pt-2">
<button
type="button"
onClick={() => {
soundFx.playClick();
onClose();
}}
className="btn-modern-secondary py-2 px-4"
>
{t('cancel')}
</button>
<button type="submit" className="btn-modern-primary py-2 px-5 font-bold">
{t('save')}
</button>
</div>
</form>
</div>
</div>
);
};