fix(admin-schedule): 공용폼 토글 정렬·멤버 필터·날짜미정 연월 드롭다운

- 날짜미정 토글을 검증된 패턴(relative w-11 + absolute translate-x-5)으로
  교체해 상하/좌우 여백 균일화
- 멤버 목록을 현재 활동 멤버만(is_former 제외)으로 필터
- 날짜미정일 때 달력 대신 연/월 드롭다운으로 입력(YYYY-MM-01 저장)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-06-16 22:10:44 +09:00
parent 72c65021fb
commit 71b678a90b

View file

@ -46,12 +46,14 @@ function ScheduleForm() {
queryFn: categoriesApi.getCategories,
staleTime: 10 * 60 * 1000,
});
const { data: members = [] } = useQuery({
const { data: allMembers = [] } = useQuery({
queryKey: ['members'],
queryFn: getMembers,
staleTime: 10 * 60 * 1000,
});
// ( )
const members = useMemo(() => allMembers.filter((m) => !m.is_former), [allMembers]);
const categories = useMemo(
() => allCategories.filter((c) => SHARED_CATEGORIES.includes(c.name)),
[allCategories]
@ -101,7 +103,23 @@ function ScheduleForm() {
}));
const setPrecision = (month) =>
setFormData((p) => ({ ...p, datePrecision: month ? 'month' : 'day', time: month ? '' : p.time }));
setFormData((p) => {
if (!month) return { ...p, datePrecision: 'day' };
// : 1
const hasMonthDate = /^\d{4}-\d{2}-01$/.test(p.date);
const now = new Date();
const date = hasMonthDate
? p.date
: `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-01`;
return { ...p, datePrecision: 'month', time: '', date };
});
// /
const yearNow = new Date().getFullYear();
const YEAR_OPTIONS = [yearNow - 1, yearNow, yearNow + 1, yearNow + 2];
const [selYear, selMonth] = (formData.date || '').split('-');
const setMonthDate = (year, monthNum) =>
setFormData((p) => ({ ...p, date: `${year}-${String(monthNum).padStart(2, '0')}-01` }));
const handleSubmit = async (e) => {
e.preventDefault();
@ -240,13 +258,13 @@ function ScheduleForm() {
<button
type="button"
onClick={() => setPrecision(!isMonthPrecision)}
className={`relative w-12 h-6 rounded-full transition-colors ${
className={`relative flex-shrink-0 w-11 h-6 rounded-full transition-colors ${
isMonthPrecision ? 'bg-primary' : 'bg-gray-300'
}`}
>
<span
className={`absolute top-0.5 w-5 h-5 bg-white rounded-full shadow transition-all ${
isMonthPrecision ? 'left-6' : 'left-0.5'
className={`absolute top-0.5 left-0.5 w-5 h-5 bg-white rounded-full shadow transition-transform ${
isMonthPrecision ? 'translate-x-5' : ''
}`}
/>
</button>
@ -255,27 +273,49 @@ function ScheduleForm() {
{/* 날짜 + 시간 */}
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
{isMonthPrecision ? '월 *' : '날짜 *'}
</label>
<DatePicker
value={formData.date}
onChange={(date) => setFormData({ ...formData, date })}
minYear={2017}
/>
{isMonthPrecision && (
<p className="text-xs text-gray-400 mt-1">선택한 날짜의 "월" 사용됩니다 (일자는 무시)</p>
)}
</div>
{!isMonthPrecision && (
{isMonthPrecision ? (
// : +
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">시간</label>
<TimePicker
value={formData.time}
onChange={(time) => setFormData({ ...formData, time })}
/>
<label className="block text-sm font-medium text-gray-700 mb-2"> / *</label>
<div className="flex gap-3">
<select
value={selYear || yearNow}
onChange={(e) => setMonthDate(e.target.value, parseInt(selMonth, 10))}
className="flex-1 px-4 py-3 border border-gray-200 rounded-xl bg-white focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
>
{YEAR_OPTIONS.map((y) => (
<option key={y} value={y}>{y}</option>
))}
</select>
<select
value={parseInt(selMonth, 10) || ''}
onChange={(e) => setMonthDate(selYear || yearNow, e.target.value)}
className="flex-1 px-4 py-3 border border-gray-200 rounded-xl bg-white focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
>
{Array.from({ length: 12 }, (_, i) => i + 1).map((m) => (
<option key={m} value={m}>{m}</option>
))}
</select>
</div>
</div>
) : (
<>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">날짜 *</label>
<DatePicker
value={formData.date}
onChange={(date) => setFormData({ ...formData, date })}
minYear={2017}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">시간</label>
<TimePicker
value={formData.time}
onChange={(time) => setFormData({ ...formData, time })}
/>
</div>
</>
)}
</div>
</div>