__('Skill tag is required.'), 'till.required' => __('Expire date is required.'), 'till.date' => __('Expire date must be a valid date.'), 'till.after' => __('Expire date must be in the future.'), 'till.before_or_equal'=> __('Expire date exceeds the maximum allowed period.'), ]; } public function getTillMaxDays(): ?int { $callableType = $this->call->callable_type ?? session('activeProfileType'); if ($callableType && $callableType !== \App\Models\User::class) { return timebank_config('calls.till_max_days_non_user'); } return timebank_config('calls.till_max_days'); } protected function rules(): array { $tillMaxDays = $this->getTillMaxDays(); $tillRule = 'required|date|after:today'; if ($tillMaxDays !== null) { $tillRule .= '|before_or_equal:' . now()->addDays($tillMaxDays)->format('Y-m-d'); } return [ 'content' => ['required', 'string', 'max:' . timebank_config('calls.content_max_input', 200)], 'till' => $tillRule, 'tagId' => 'required|integer|exists:taggable_tags,tag_id', 'country' => 'required|integer|exists:countries,id', 'city' => 'nullable|integer|exists:cities,id', 'district'=> 'nullable|integer|exists:districts,id', 'translationContents.*' => ['nullable', 'string', 'max:' . timebank_config('calls.content_max_input', 200)], ]; } /** * Recompute the locales the selected Tag has translations for (excluding the base locale), * and drop any already-added translation whose locale is no longer available. */ public function refreshAvailableTagLocales(): void { if (!$this->tagId) { $this->availableTagLocales = []; $this->translationContents = []; return; } $tag = Tag::find($this->tagId); $this->availableTagLocales = $tag ? $tag->translations()->pluck('locale')->unique()->reject(fn($locale) => $locale === App::getLocale())->values()->all() : []; $this->translationContents = collect($this->translationContents) ->only($this->availableTagLocales) ->all(); } public function getRemainingTagLocalesProperty(): array { return collect($this->availableTagLocales) ->reject(fn($locale) => array_key_exists($locale, $this->translationContents)) ->values() ->all(); } public function addTranslation(): void { if ( $this->newTranslationLocale && in_array($this->newTranslationLocale, $this->availableTagLocales) && !array_key_exists($this->newTranslationLocale, $this->translationContents) ) { $this->translationContents[$this->newTranslationLocale] = ''; } $this->newTranslationLocale = ''; } public function removeTranslation(string $locale): void { unset($this->translationContents[$locale]); } public function openModal(): void { $this->resetValidation(); // Pre-fill from existing call $this->tagId = $this->call->tag_id; $this->content = $this->call->translations->where('locale', App::getLocale())->first()?->content ?? $this->call->translations->first()?->content ?? ''; $this->till = $this->call->till?->format('Y-m-d'); $this->isPublic = (bool) $this->call->is_public; $location = $this->call->location; $this->country = $location?->country_id; $this->division = $location?->division_id; $this->city = $location?->city_id; $this->district = $location?->district_id; $this->refreshAvailableTagLocales(); // Pre-fill any existing translations for locales the tag currently supports $this->translationContents = $this->call->translations ->whereIn('locale', $this->availableTagLocales) ->pluck('content', 'locale') ->map(fn($content) => $content ?? '') ->all(); $this->showModal = true; } public function callTagSelected(int $tagId): void { $this->tagId = $tagId; $this->resetValidation('tagId'); $this->refreshAvailableTagLocales(); } public function callTagCleared(): void { $this->tagId = null; $this->refreshAvailableTagLocales(); } public function countryToParent($value): void { $this->country = $value ?: null; } public function divisionToParent($value): void { $this->division = $value ?: null; } public function cityToParent($value): void { $this->city = $value ?: null; } public function districtToParent($value): void { $this->district = $value ?: null; } public function confirmDelete(): void { $this->showDeleteConfirm = true; } public function delete(): void { $activeProfile = getActiveProfile(); if (!$activeProfile || get_class($activeProfile) !== $this->call->callable_type || $activeProfile->id !== $this->call->callable_id) { abort(403); } $this->call->unsearchable(); $this->call->translations()->delete(); $this->call->delete(); $this->redirect(request()->header('Referer') ?: route(\Illuminate\Support\Facades\Auth::check() ? 'main' : 'welcome')); } public function save(): void { // Only the callable owner may edit $activeProfile = getActiveProfile(); if (!$activeProfile || get_class($activeProfile) !== $this->call->callable_type || $activeProfile->id !== $this->call->callable_id) { abort(403); } $this->validate(); // Resolve or create a standalone Location record $locationId = null; if ($this->country || $this->city) { $attributes = array_filter([ 'country_id' => $this->country ?: null, 'division_id' => $this->division ?: null, 'city_id' => $this->city ?: null, 'district_id' => $this->district ?: null, ]); $location = Location::whereNull('locatable_id') ->whereNull('locatable_type') ->where($attributes) ->first(); if (!$location) { $location = new Location($attributes); $location->save(); } $locationId = $location->id; } $this->call->update([ 'tag_id' => $this->tagId, 'location_id' => $locationId, 'till' => $this->till ?: null, 'is_public' => $this->isPublic, ]); // Update or create translation for current locale CallTranslation::updateOrCreate( ['call_id' => $this->call->id, 'locale' => App::getLocale()], ['content' => $this->content ?: null] ); foreach ($this->translationContents as $locale => $translatedContent) { if ($translatedContent !== '' && $translatedContent !== null) { CallTranslation::updateOrCreate( ['call_id' => $this->call->id, 'locale' => $locale], ['content' => $translatedContent] ); } else { CallTranslation::where('call_id', $this->call->id)->where('locale', $locale)->delete(); } } // Remove translations for locales that were removed from the form (but keep the base locale) CallTranslation::where('call_id', $this->call->id) ->where('locale', '!=', App::getLocale()) ->whereNotIn('locale', array_keys($this->translationContents)) ->delete(); $this->call->searchable(); $this->showModal = false; $this->notification()->success( title: __('Saved'), description: __('Your Call has been updated.') ); $this->redirect(request()->header('Referer') ?: route('call.show', ['id' => $this->call->id])); } public function render() { return view('livewire.calls.edit', [ 'profileName' => $this->call->callable?->name ?? '', ]); } }