mailwolt/resources/views/livewire/ui/mail/modal/alias-form-modal.blade.php

322 lines
18 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

@push('modal.header')
<div class="px-5 pt-5 pb-3 border-b border-white/10 backdrop-blur rounded-t-2xl">
<div class="flex items-center justify-between">
<div>
<h2 class="text-lg font-semibold text-white">
{{ $aliasId ? 'Alias bearbeiten' : 'Alias anlegen' }}
</h2>
<p class="text-[13px] text-white/60">
{{ $aliasId ? 'Passe den Alias und seine Empfänger an.' : 'Lege Adresse und Empfänger fest.' }}
</p>
</div>
<button wire:click="$dispatch('closeModal')" class="text-white/60 hover:text-white text-lg">
<i class="ph ph-x"></i>
</button>
</div>
</div>
@endpush
<div class="p-6 space-y-5">
{{-- alles in ein Formular, wie beim Limits-Modal --}}
<form id="alias-form" wire:submit.prevent="save" class="space-y-4">
{{-- Domain + Adresse + Status --}}
<div class="flex items-end">
<label class="inline-flex items-center gap-3 select-none">
<input type="checkbox" wire:model="is_active"
class="peer appearance-none w-5 h-5 rounded-md border border-emerald-500/50 bg-transparent
checked:bg-emerald-500 checked:border-emerald-400 grid place-content-center transition">
<span class="text-slate-200">Alias aktivieren</span>
</label>
</div>
{{-- Row 1: Domain + Typ --}}
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
{{-- DOMAIN (TailwindPlus Elements) --}}
<div class="relative" wire:ignore id="domain-select-{{ $this->getId() }}">
<label class="block text-xs text-white/60 mb-1">Domain</label>
<el-select id="el-domain-{{ $this->getId() }}" name="domain_id" class="block w-full">
{{-- Trigger --}}
<button type="button"
class="grid w-full grid-cols-1 cursor-default rounded-2xl bg-white/5 border border-white/10 px-3.5 h-11 text-white/90">
<el-selectedcontent class="col-start-1 row-start-1 flex items-center gap-2 pr-6">
<i class="ph ph-globe-hemisphere-west text-white/60 text-[16px]"></i>
<span class="block truncate" data-selected-label>
{{ optional($domain)->domain ?? 'Domain wählen' }}
</span>
</el-selectedcontent>
<i class="ph ph-caret-down col-start-1 row-start-1 self-center justify-self-end text-white/50"></i>
</button>
{{-- Optionen --}}
<el-options anchor="bottom start" popover
class="max-h-60 w-(--button-width) overflow-auto rounded-2xl bg-gray-900/95 backdrop-blur
py-1 text-base outline-1 -outline-offset-1 outline-white/10 shadow-xl sm:text-sm
data-leave:transition data-leave:duration-100 data-leave:ease-in data-closed:data-leave:opacity-0">
@foreach($domains as $d)
<el-option
value="{{ $d->id }}"
data-value="{{ $d->id }}"
data-label="{{ $d->domain }}"
@if($domain && $domain->id === $d->id) aria-selected="true" @endif
class="group/option relative block cursor-default py-2 pr-9 pl-3 text-white/90 select-none
hover:bg-white/5 focus:bg-white/10 focus:text-white focus:outline-hidden"
onclick="(function(el){
const root = el.closest('#domain-select-{{ $this->getId() }}');
root.querySelectorAll('el-option').forEach(o => o.removeAttribute('aria-selected'));
el.setAttribute('aria-selected','true');
const labelEl = root.querySelector('[data-selected-label]');
if (labelEl) { labelEl.textContent = el.dataset.label; }
@this.set('domainId', parseInt(el.dataset.value, 10));
root.querySelector('button')?.focus();
})(this)">
<div class="flex items-center gap-2">
<i class="ph ph-globe-hemisphere-west text-white/60"></i>
<span
class="block truncate group-aria-selected/option:font-semibold">{{ $d->domain }}</span>
</div>
<span class="absolute inset-y-0 right-0 hidden items-center pr-3 text-emerald-300
group-aria-selected/option:flex in-[el-selectedcontent]:hidden">
<i class="ph ph-check text-[18px]"></i>
</span>
</el-option>
@endforeach
</el-options>
</el-select>
@error('domainId')
<div class="text-rose-300 text-xs mt-1">{{ $message }}</div> @enderror
</div>
{{-- TYP (TailwindPlus Elements) --}}
<div class="relative" wire:ignore id="type-select-{{ $this->getId() }}">
<label class="block text-xs text-white/60 mb-1">Typ</label>
<el-select id="el-type-{{ $this->getId() }}" name="alias_type" class="block w-full">
{{-- Trigger --}}
<button type="button"
class="grid w-full grid-cols-1 cursor-default rounded-2xl bg-white/5 border border-white/10 px-3.5 h-11 text-white/90">
<el-selectedcontent class="col-start-1 row-start-1 flex items-center gap-2 pr-6">
<i class="ph {{ $type === 'group' ? 'ph-users' : 'ph-user' }} text-white/60 text-[16px]"></i>
<span class="block truncate" data-selected-label-type>
{{ $type === 'group' ? 'Gruppe' : 'Single' }}
</span>
</el-selectedcontent>
<i class="ph ph-caret-down col-start-1 row-start-1 self-center justify-self-end text-white/50"></i>
</button>
{{-- Optionen --}}
<el-options anchor="bottom start" popover
class="max-h-60 w-(--button-width) overflow-auto rounded-2xl bg-gray-900/95 backdrop-blur
py-1 text-base outline-1 -outline-offset-1 outline-white/10 shadow-xl sm:text-sm
data-leave:transition data-leave:duration-100 data-leave:ease-in data-closed:data-leave:opacity-0">
{{-- Single --}}
<el-option data-value="single" data-label="Single"
@if($type === 'single') aria-selected="true" @endif
class="group/option relative block cursor-default py-2 pr-9 pl-3 text-white/90 select-none
hover:bg-white/5 focus:bg-white/10 focus:text-white focus:outline-hidden"
onclick="(function(el){
const root = el.closest('#type-select-{{ $this->getId() }}');
root.querySelectorAll('el-option').forEach(o => o.removeAttribute('aria-selected'));
el.setAttribute('aria-selected','true');
const lbl = root.querySelector('[data-selected-label-type]');
if (lbl) { lbl.textContent = el.dataset.label; }
// Icon im Trigger wechseln
const icon = root.querySelector('.ph-user, .ph-users');
if (icon) { icon.className = 'ph ph-user text-white/60 text-[16px]'; }
@this.set('type', 'single');
root.querySelector('button')?.focus();
})(this)">
<div class="flex items-center gap-2">
<i class="ph ph-user text-white/60"></i>
<span class="block truncate group-aria-selected/option:font-semibold">Single</span>
</div>
<span class="absolute inset-y-0 right-0 hidden items-center pr-3 text-emerald-300
group-aria-selected/option:flex in-[el-selectedcontent]:hidden">
<i class="ph ph-check text-[18px]"></i>
</span>
</el-option>
{{-- Gruppe --}}
<el-option data-value="group" data-label="Gruppe"
@if($type === 'group') aria-selected="true" @endif
class="group/option relative block cursor-default py-2 pr-9 pl-3 text-white/90 select-none
hover:bg-white/5 focus:bg-white/10 focus:text-white focus:outline-hidden"
onclick="(function(el){
const root = el.closest('#type-select-{{ $this->getId() }}');
root.querySelectorAll('el-option').forEach(o => o.removeAttribute('aria-selected'));
el.setAttribute('aria-selected','true');
const lbl = root.querySelector('[data-selected-label-type]');
if (lbl) { lbl.textContent = el.dataset.label; }
const icon = root.querySelector('.ph-user, .ph-users');
if (icon) { icon.className = 'ph ph-users text-white/60 text-[16px]'; }
@this.set('type', 'group');
root.querySelector('button')?.focus();
})(this)">
<div class="flex items-center gap-2">
<i class="ph ph-users text-white/60"></i>
<span class="block truncate group-aria-selected/option:font-semibold">Gruppe</span>
</div>
<span class="absolute inset-y-0 right-0 hidden items-center pr-3 text-emerald-300
group-aria-selected/option:flex in-[el-selectedcontent]:hidden">
<i class="ph ph-check text-[18px]"></i>
</span>
</el-option>
</el-options>
</el-select>
@error('type')
<div class="text-rose-300 text-xs mt-1">{{ $message }}</div> @enderror
</div>
</div>
{{-- Row 2: Adresse (volle Breite, gleiche Höhe) --}}
<div>
<label class="block text-xs text-white/60 mb-1">Adresse</label>
<div class="flex">
<input type="text" wire:model.defer="local" placeholder="info"
class="flex-1 rounded-l-2xl bg-white/5 border border-white/10 text-white px-3 h-11 text-sm focus:border-white/20 focus:ring-0">
<span
class="inline-flex items-center px-3 rounded-r-2xl border border-l-0 border-white/10 bg-white/5 text-white/70 text-sm h-11">
@ {{ optional($domain)->domain }}
</span>
</div>
@error('local')
<div class="mt-1 text-xs text-rose-300">{{ $message }}</div> @enderror
</div>
@if($type === 'group')
<div>
<label class="block text-xs text-white/60 mb-1">Gruppenname (optional)</label>
<input type="text" wire:model.defer="group_name"
class="w-full rounded-lg bg-white/5 border border-white/10 text-white px-3 h-11 text-sm focus:border-white/20 focus:ring-0"
placeholder="z. B. Office Gruppe">
@error('group_name') <div class="mt-1 text-xs text-rose-300">{{ $message }}</div> @enderror
</div>
@endif
{{-- Empfänger --}}
<div class="space-y-3">
<div class="flex items-center justify-between">
<h3 class="text-sm text-white/80">Empfänger</h3>
<div class="text-end">
@if($type === 'single')
<div class="text-[11px] text-white/50 mt-1">Bei „Single“ ist nur ein Empfänger erlaubt.</div>
@else
<button type="button"
wire:click="addRecipientRow"
class="inline-flex items-center gap-1.5 rounded-lg border border-white/10 bg-white/5 px-2.5 py-1 text-xs
text-white/80 hover:text-white hover:border-white/20 disabled:opacity-40 disabled:cursor-not-allowed"
@disabled(! $canAddRecipient)>
<i class="ph ph-plus"></i> Empfänger
</button>
@endif
</div>
</div>
@error('recipients')
<div class="text-xs text-rose-300">{{ $message }}</div>
@enderror
{{-- WICHTIG: stabiler Container-Key um die Liste --}}
<div class="space-y-4" wire:key="recipients-container">
@foreach ($recipients as $idx => $r)
<div class="rounded-xl border border-white/10 bg-white/[0.04] p-3"
wire:key="recipient-{{ $r['id'] }}">
{{-- Labels (dynamisches Grid 3 oder 4 Spalten je nach Typ) --}}
<div class="grid {{ $type === 'single' ? 'grid-cols-[5fr_auto_5fr]' : 'grid-cols-[5fr_auto_5fr_auto]' }} gap-3 mb-1 text-xs text-white/60">
<div>Interner Empfänger (Postfach)</div>
<div></div>
<div>Externe E-Mail</div>
@if($type === 'group')
<div></div>
@endif
</div>
{{-- Eingaben + oder + (optional) Löschen --}}
<div class="grid {{ $type === 'single' ? 'grid-cols-[5fr_auto_5fr]' : 'grid-cols-[5fr_auto_5fr_auto]' }} gap-3 items-center">
{{-- Interner Empfänger --}}
<div>
<select
wire:model.live="recipients.{{ $idx }}.mail_user_id"
class="w-full h-11 rounded-2xl bg-white/5 border border-white/10 text-white px-3 text-sm
focus:border-white/20 focus:ring-0 disabled:opacity-40 disabled:cursor-not-allowed"
@disabled($rowState[$idx]['disable_internal'] ?? false)>
<option value=""></option>
@foreach($domainMailUsers as $mu)
<option value="{{ $mu->id }}"
@disabled(in_array($mu->id, $disabledMailboxIdsByRow[$idx] ?? [], true))>
{{ $mu->localpart . '@' . optional($domain)->domain }}
</option>
@endforeach
</select>
</div>
{{-- ODER --}}
<div class="flex items-center justify-center text-white/50 select-none">oder</div>
{{-- Externe E-Mail --}}
<div>
<input type="email"
wire:model.live="recipients.{{ $idx }}.email"
placeholder="user@example.com"
class="w-full h-11 rounded-2xl bg-white/5 border border-white/10 text-white px-3 text-sm
focus:border-white/20 focus:ring-0 disabled:opacity-40 disabled:cursor-not-allowed"
@disabled($rowState[$idx]['disable_external'] ?? false)>
@error("recipients.$idx.email")
<div class="mt-1 text-xs text-rose-300">{{ $message }}</div>
@enderror
</div>
{{-- Löschen (nur bei Gruppe sichtbar) --}}
@if($type === 'group')
<div class="flex items-center justify-center">
<button type="button"
wire:click="removeRecipientRow({{ $idx }})"
class="size-7 grid place-items-center rounded-lg bg-rose-500/20 text-rose-200
border border-rose-400/40 hover:bg-rose-500/30
disabled:opacity-40 disabled:cursor-not-allowed">
<i class="ph ph-trash-simple text-base"></i>
</button>
</div>
@endif
</div>
</div>
@endforeach
</div>
@if($type === 'single' && count($recipients) > 1)
<div class="text-xs text-amber-300">
Hinweis: Bei „Single“ wird nur der erste Empfänger gespeichert.
</div>
@endif
</div>
<div>
<label class="block text-xs text-white/60 mb-1">Notizen (optional)</label>
<textarea wire:model.defer="notes" rows="3"
class="w-full rounded-lg bg-white/5 border border-white/10 text-white px-3 py-2 text-sm focus:border-white/20 focus:ring-0"></textarea>
@error('notes')
<div class="mt-1 text-xs text-rose-300">{{ $message }}</div> @enderror
</div>
</form>
</div>
@push('modal.footer')
<div class="px-5 py-3 border-t border-white/10 backdrop-blur rounded-b-2xl">
<div class="flex justify-end gap-2">
<button type="button" wire:click="$dispatch('closeModal')"
class="px-4 py-2 rounded-lg text-sm border border-white/10 text-white/70 hover:text-white hover:border-white/20">
Abbrechen
</button>
<button type="submit" form="alias-form"
class="px-4 py-2 rounded-lg text-sm bg-emerald-500/20 text-emerald-300 border border-emerald-400/30 hover:bg-emerald-500/30">
{{ $aliasId ? 'Speichern' : 'Anlegen' }}
</button>
</div>
</div>
@endpush