feat(festival-bot): 다이얼로그에 활성 월 선택 UI

축제 봇 추가/수정 다이얼로그에 1~12월 토글 그리드 + 전체 선택/해제
추가. 신규 봇은 전체 월(항상 실행) 기본. 전체 선택은 active_months
null로 저장.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-06-06 22:58:13 +09:00
parent 8b36e9b5f7
commit 2af3af9345

View file

@ -17,6 +17,8 @@ const INTERVAL_OPTIONS = [
{ value: 1440, label: '24시간' }, { value: 1440, label: '24시간' },
]; ];
const ALL_MONTHS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
/** /**
* 커스텀 드롭다운 (Portal 사용) * 커스텀 드롭다운 (Portal 사용)
*/ */
@ -118,8 +120,17 @@ function FestivalBotDialog({ isOpen, onClose, botId = null, onSuccess }) {
const [name, setName] = useState(''); const [name, setName] = useState('');
const [searchUrl, setSearchUrl] = useState(''); const [searchUrl, setSearchUrl] = useState('');
const [interval, setInterval] = useState(360); const [interval, setInterval] = useState(360);
const [activeMonths, setActiveMonths] = useState(ALL_MONTHS);
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
const allMonthsSelected = activeMonths.length === ALL_MONTHS.length;
const toggleMonth = (m) =>
setActiveMonths((prev) =>
prev.includes(m) ? prev.filter((x) => x !== m) : [...prev, m].sort((a, b) => a - b)
);
const toggleAllMonths = () =>
setActiveMonths(allMonthsSelected ? [] : [...ALL_MONTHS]);
// ( ) // ( )
const { data: bot, isLoading: botLoading } = useQuery({ const { data: bot, isLoading: botLoading } = useQuery({
queryKey: ['admin', 'festival-bot', botId], queryKey: ['admin', 'festival-bot', botId],
@ -137,11 +148,18 @@ function FestivalBotDialog({ isOpen, onClose, botId = null, onSuccess }) {
setName(bot.name || ''); setName(bot.name || '');
setSearchUrl(bot.search_url || ''); setSearchUrl(bot.search_url || '');
setInterval(bot.cron_interval || 360); setInterval(bot.cron_interval || 360);
// active_months: null() ,
setActiveMonths(
Array.isArray(bot.active_months) && bot.active_months.length > 0
? bot.active_months
: [...ALL_MONTHS]
);
} else if (!botId) { } else if (!botId) {
// // (: = )
setName(''); setName('');
setSearchUrl(''); setSearchUrl('');
setInterval(360); setInterval(360);
setActiveMonths([...ALL_MONTHS]);
} }
}, [isOpen, bot, botId]); }, [isOpen, bot, botId]);
@ -156,6 +174,8 @@ function FestivalBotDialog({ isOpen, onClose, botId = null, onSuccess }) {
name: name.trim(), name: name.trim(),
search_url: searchUrl.trim(), search_url: searchUrl.trim(),
cron_interval: interval, cron_interval: interval,
// ( ) (null)
active_months: allMonthsSelected ? null : activeMonths,
}; };
if (isEdit) { if (isEdit) {
@ -261,6 +281,42 @@ function FestivalBotDialog({ isOpen, onClose, botId = null, onSuccess }) {
placeholder="간격 선택" placeholder="간격 선택"
/> />
</div> </div>
{/* 활성 월 */}
<div>
<div className="flex items-center justify-between mb-1.5">
<label className="text-sm font-medium text-gray-700">활성 </label>
<button
type="button"
onClick={toggleAllMonths}
className="text-xs font-medium text-emerald-600 hover:text-emerald-700"
>
{allMonthsSelected ? '전체 해제' : '전체 선택'}
</button>
</div>
<div className="grid grid-cols-6 gap-1.5">
{ALL_MONTHS.map((m) => {
const on = activeMonths.includes(m);
return (
<button
key={m}
type="button"
onClick={() => toggleMonth(m)}
className={`py-2 rounded-lg text-sm font-medium transition-colors ${
on
? 'bg-emerald-500 text-white'
: 'bg-gray-100 text-gray-400 hover:bg-gray-200'
}`}
>
{m}
</button>
);
})}
</div>
<p className="text-xs text-gray-400 mt-1.5">
선택한 월에만 봇이 실행됩니다. 전체 선택 항상 실행됩니다.
</p>
</div>
</form> </form>
)} )}