input('year', now()->year); $month = (int) $request->input('month', now()->month); $tenantId = session('selected_tenant_id', 1); $firstDay = Carbon::create($year, $month, 1); $lastDay = $firstDay->copy()->endOfMonth(); $startOfWeek = $firstDay->copy()->startOfWeek(Carbon::SUNDAY); $endOfWeek = $lastDay->copy()->endOfWeek(Carbon::SATURDAY); $calendarData = Schedule::forTenant($tenantId) ->active() ->betweenDates($startOfWeek->toDateString(), $endOfWeek->toDateString()) ->orderBy('start_date') ->orderBy('start_time') ->get() ->groupBy(fn ($s) => $s->start_date->format('Y-m-d')); $holidayMap = $this->getHolidayMap($tenantId, $year, $month); return view('dashboard.partials.calendar', compact( 'year', 'month', 'calendarData', 'holidayMap' )); } /** * 일정 등록 */ public function store(Request $request): JsonResponse { $validated = $request->validate([ 'title' => 'required|string|max:255', 'description' => 'nullable|string|max:1000', 'start_date' => 'required|date', 'end_date' => 'nullable|date|after_or_equal:start_date', 'start_time' => 'nullable|date_format:H:i', 'end_time' => 'nullable|date_format:H:i', 'is_all_day' => 'boolean', 'type' => 'required|in:event,meeting,notice,other', 'color' => 'nullable|string|max:20', ]); $tenantId = session('selected_tenant_id', 1); $validated['tenant_id'] = $tenantId; $validated['created_by'] = auth()->id(); $validated['is_all_day'] = $validated['is_all_day'] ?? true; if (empty($validated['end_date'])) { $validated['end_date'] = $validated['start_date']; } $schedule = Schedule::create($validated); return response()->json([ 'success' => true, 'message' => '일정이 등록되었습니다.', 'data' => $schedule, ]); } /** * 일정 상세 (JSON) */ public function show(int $id): JsonResponse { $tenantId = session('selected_tenant_id', 1); $schedule = Schedule::forTenant($tenantId)->findOrFail($id); return response()->json([ 'success' => true, 'data' => $schedule, ]); } /** * 일정 수정 */ public function update(Request $request, int $id): JsonResponse { $validated = $request->validate([ 'title' => 'required|string|max:255', 'description' => 'nullable|string|max:1000', 'start_date' => 'required|date', 'end_date' => 'nullable|date|after_or_equal:start_date', 'start_time' => 'nullable|date_format:H:i', 'end_time' => 'nullable|date_format:H:i', 'is_all_day' => 'boolean', 'type' => 'required|in:event,meeting,notice,other', 'color' => 'nullable|string|max:20', ]); $tenantId = session('selected_tenant_id', 1); $schedule = Schedule::forTenant($tenantId)->findOrFail($id); $validated['updated_by'] = auth()->id(); $validated['is_all_day'] = $validated['is_all_day'] ?? true; if (empty($validated['end_date'])) { $validated['end_date'] = $validated['start_date']; } $schedule->update($validated); return response()->json([ 'success' => true, 'message' => '일정이 수정되었습니다.', 'data' => $schedule->fresh(), ]); } /** * 일정 삭제 */ public function destroy(int $id): JsonResponse { $tenantId = session('selected_tenant_id', 1); $schedule = Schedule::forTenant($tenantId)->findOrFail($id); $schedule->update(['deleted_by' => auth()->id()]); $schedule->delete(); return response()->json([ 'success' => true, 'message' => '일정이 삭제되었습니다.', ]); } /** * 해당 월의 휴일 맵 생성 (날짜 => 휴일명) */ private function getHolidayMap(int $tenantId, int $year, int $month): array { $startOfMonth = Carbon::create($year, $month, 1)->startOfWeek(Carbon::SUNDAY); $endOfMonth = Carbon::create($year, $month, 1)->endOfMonth()->endOfWeek(Carbon::SATURDAY); $holidays = Holiday::forTenant($tenantId) ->where('start_date', '<=', $endOfMonth->toDateString()) ->where('end_date', '>=', $startOfMonth->toDateString()) ->get(); $map = []; foreach ($holidays as $holiday) { $start = $holiday->start_date->copy(); $end = $holiday->end_date->copy(); for ($d = $start; $d->lte($end); $d->addDay()) { $map[$d->format('Y-m-d')] = $holiday->name; } } return $map; } }