route('calendar.settings.create'); } /** * Create a local calendar **/ public function createForm(Request $request) { $user = $request->user(); $data = [ 'title' => __('calendar.settings.create.title'), 'sub' => __('calendar.settings.create.subtitle'), 'defaults' => [ 'name' => '', 'description' => '', 'timezone' => $user->timezone ?? config('app.timezone', 'UTC'), 'color' => default_calendar_color(), ], 'redirect' => route('calendar.settings'), ]; if ($request->header('HX-Request')) { $data['redirect'] = route('calendar.index'); return view('calendar.partials.create-modal', $data); } return $this->frame('calendar.settings.create', $data); } public function createStore(Request $request, CreateCalendar $creator) { $data = $request->validate([ 'name' => 'required|string|max:100', 'description' => 'nullable|string|max:255', 'timezone' => 'required|string', 'color' => 'nullable|regex:/^#[0-9A-Fa-f]{6}$/', ]); $creator->create($request->user(), $data); $redirect = $data['redirect'] ?? route('calendar.index'); return redirect($redirect)->with('toast', [ 'message' => __('Calendar created!'), 'type' => 'success', ]); } /** * Subscribe **/ /* show “Subscribe to a calendar” form */ public function subscribeForm() { return $this->frame( 'calendar.settings.subscribe', [ 'title' => __('calendar.settings.subscribe.title'), 'sub' => __('calendar.settings.subscribe.subtitle'), ]); } /* handle POST from the subscribe form */ public function subscribeStore(Request $request) { $data = $request->validate([ 'source' => ['required', 'url'], 'displayname' => ['nullable', 'string', 'max:100'], 'color' => ['nullable', 'regex:/^#[0-9A-F]{6}$/i'], ]); // create the calendarsubscription and calendar_meta rows in one call via Subscription model Subscription::createWithMeta( $request->user(), [ 'source' => $data['source'], 'displayname' => $data['displayname'] ?: $data['source'], 'calendarcolor' => calendar_color($data), // you can add 'refreshrate' => 'P1D' here if you like ] ); return redirect() ->route('calendar.index') ->with('toast', __('Subscription added successfully!')); } /** * individual calendar settings */ public function calendarForm(Request $request, string $calendarUri) { $user = $request->user(); $principalUri = $user->uri; // this is the user's "instance" of the calendar (displayname/color/etc live here in sabre) $instance = CalendarInstance::query() ->where('principaluri', $principalUri) ->where('uri', $calendarUri) ->firstOrFail(); // your app meta (optional row) $meta = $instance->meta; // if it's remote $icsUrl = null; if (($meta?->is_remote ?? false) && $meta?->subscription_id) { $icsUrl = Subscription::query() ->whereKey($meta->subscription_id) ->value('source'); } return $this->frame( 'calendar.settings.calendar', [ 'title' => __('calendar.settings.calendar.title'), 'sub' => __('calendar.settings.calendar.subtitle'), 'instance' => $instance, 'meta' => $meta, 'icsUrl' => $icsUrl, 'userTz' => $user->timezone, ]); } public function calendarStore(Request $request, string $calendarUri): RedirectResponse { $user = $request->user(); $principalUri = $user->uri; $instance = CalendarInstance::query() ->where('principaluri', $principalUri) ->where('uri', $calendarUri) ->with('meta') ->firstOrFail(); $data = $request->validate([ 'displayname' => ['required', 'string', 'max:100'], 'description' => ['nullable', 'string', 'max:500'], 'timezone' => ['nullable', 'string', 'max:64'], 'color' => ['nullable', 'regex:/^#[0-9A-F]{6}$/i'], ]); $timezone = filled($data['timezone'] ?? null) ? $data['timezone'] : $user->timezone; $color = $data['color'] ?? $instance->resolvedColor(); DB::transaction(function () use ($instance, $data, $timezone, $color) { // update sabre calendar instance (dav-facing) $instance->update([ 'displayname' => $data['displayname'], 'description' => $data['description'] ?? null, 'timezone' => $timezone, 'calendarcolor' => $color, ]); // update ui meta (kithkin-facing) CalendarMeta::updateOrCreate( ['calendar_id' => $instance->calendarid], [ 'title' => $data['displayname'], 'color' => $color, 'color_fg' => contrast_text_color($color), ] ); }); return Redirect::route('calendar.settings.calendars.show', $calendarUri) ->with('toast', [ 'message' => __('calendar.settings.saved'), 'type' => 'success', ]); } /** * content frame handler */ private function frame(?string $view = null, array $data = []) { $user = request()->user(); /* pull user's calendar instances and adapt ordering keys to calendarorder */ $calendars = CalendarInstance::query() ->forUser($user) ->withUiMeta() ->ordered() ->get(); return view('calendar.settings.index', [ 'view' => $view, 'data' => $data, 'calendars' => $calendars, 'timezones' => config('timezones'), ]); } }