feature/v2-unified-renewal #379

Merged
kjs merged 145 commits from feature/v2-unified-renewal into main 2026-02-03 12:11:19 +09:00
2 changed files with 33 additions and 24 deletions
Showing only changes of commit 4e7aa0c3b9 - Show all commits

View File

@ -85,11 +85,31 @@ export function TimelineSchedulerComponent({
const cellWidthConfig = config.cellWidth || defaultTimelineSchedulerConfig.cellWidth!;
const cellWidth = cellWidthConfig[zoomLevel] || 60;
// 리소스가 없으면 스케줄의 resourceId로 자동 생성
const effectiveResources = useMemo(() => {
if (resources.length > 0) {
return resources;
}
// 스케줄에서 고유한 resourceId 추출하여 자동 리소스 생성
const uniqueResourceIds = new Set<string>();
schedules.forEach((schedule) => {
if (schedule.resourceId) {
uniqueResourceIds.add(schedule.resourceId);
}
});
return Array.from(uniqueResourceIds).map((id) => ({
id,
name: id, // resourceId를 이름으로 사용
}));
}, [resources, schedules]);
// 리소스별 스케줄 그룹화
const schedulesByResource = useMemo(() => {
const grouped = new Map<string, ScheduleItem[]>();
resources.forEach((resource) => {
effectiveResources.forEach((resource) => {
grouped.set(resource.id, []);
});
@ -99,7 +119,7 @@ export function TimelineSchedulerComponent({
list.push(schedule);
} else {
// 리소스가 없는 스케줄은 첫 번째 리소스에 할당
const firstResource = resources[0];
const firstResource = effectiveResources[0];
if (firstResource) {
const firstList = grouped.get(firstResource.id);
if (firstList) {
@ -110,7 +130,7 @@ export function TimelineSchedulerComponent({
});
return grouped;
}, [schedules, resources]);
}, [schedules, effectiveResources]);
// 줌 레벨 변경
const handleZoomIn = useCallback(() => {
@ -132,12 +152,12 @@ export function TimelineSchedulerComponent({
// 스케줄 클릭 핸들러
const handleScheduleClick = useCallback(
(schedule: ScheduleItem) => {
const resource = resources.find((r) => r.id === schedule.resourceId);
const resource = effectiveResources.find((r) => r.id === schedule.resourceId);
if (resource && onScheduleClick) {
onScheduleClick({ schedule, resource });
}
},
[resources, onScheduleClick]
[effectiveResources, onScheduleClick]
);
// 빈 셀 클릭 핸들러
@ -195,13 +215,13 @@ export function TimelineSchedulerComponent({
// 추가 버튼 클릭
const handleAddClick = useCallback(() => {
if (onAddSchedule && resources.length > 0) {
if (onAddSchedule && effectiveResources.length > 0) {
onAddSchedule(
resources[0].id,
effectiveResources[0].id,
new Date().toISOString().split("T")[0]
);
}
}, [onAddSchedule, resources]);
}, [onAddSchedule, effectiveResources]);
// 디자인 모드 플레이스홀더
if (isDesignMode) {
@ -250,8 +270,8 @@ export function TimelineSchedulerComponent({
);
}
// 리소스 없음
if (resources.length === 0) {
// 리소스 없음 (스케줄도 없는 경우에만 표시)
if (effectiveResources.length === 0) {
return (
<div
className="w-full flex items-center justify-center bg-muted/10 rounded-lg"
@ -259,8 +279,8 @@ export function TimelineSchedulerComponent({
>
<div className="text-center text-muted-foreground">
<Calendar className="h-8 w-8 mx-auto mb-2" />
<p className="text-sm font-medium"> </p>
<p className="text-xs mt-1"> </p>
<p className="text-sm font-medium"> </p>
<p className="text-xs mt-1"> </p>
</div>
</div>
);
@ -385,7 +405,7 @@ export function TimelineSchedulerComponent({
{/* 리소스 행들 */}
<div>
{resources.map((resource) => (
{effectiveResources.map((resource) => (
<ResourceRow
key={resource.id}
resource={resource}

View File

@ -94,17 +94,6 @@ export function useTimelineData(
page: 1,
size: 10000,
autoFilter: true,
search: {
// 표시 범위 내의 스케줄만 조회
[fieldMapping.startDate]: {
value: toDateString(viewEndDate),
operator: "lte",
},
[fieldMapping.endDate]: {
value: toDateString(viewStartDate),
operator: "gte",
},
},
}
);