- Created Note model and controller for handling notes. - Added routes for notes CRUD operations. - Implemented notes index view with search and pinning functionality. - Created migration for notes table with necessary fields. - Developed event creation form with client and contract options.
324 lines
18 KiB
PHP
324 lines
18 KiB
PHP
@extends('layouts.app')
|
||
|
||
@section('title', 'Add Event')
|
||
@section('page-title', 'Add Event 📅')
|
||
@section('page-subtitle', 'Schedule a new task, meeting, or posting')
|
||
|
||
@section('content')
|
||
<div class="max-w-2xl mx-auto">
|
||
<div class="flex items-center gap-3 mb-5">
|
||
<a href="{{ route('schedule.index') }}"
|
||
class="text-xs px-3 py-2 rounded-full border border-pink-200 text-gray-500 hover:bg-pink-50">
|
||
← Back to Schedule
|
||
</a>
|
||
</div>
|
||
|
||
<div class="cat-card p-4 lg:p-8">
|
||
<form action="{{ route('schedule.store') }}" method="POST" id="create-event-form"
|
||
x-data="contractCheck('{{ route('contracts.check') }}')"
|
||
class="space-y-5">
|
||
@csrf
|
||
<input type="hidden" name="start_time" id="start_time_hidden">
|
||
<input type="hidden" name="end_time" id="end_time_hidden">
|
||
|
||
{{-- Title --}}
|
||
<div>
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">
|
||
Title <span class="text-pink-400">*</span>
|
||
</label>
|
||
<input type="text" name="title" value="{{ old('title') }}"
|
||
class="input-soft" placeholder="Event title" required>
|
||
@error('title') <p class="text-xs text-red-500 mt-1">{{ $message }}</p> @enderror
|
||
</div>
|
||
|
||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||
{{-- Type --}}
|
||
<div>
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">Type</label>
|
||
<select name="event_type" class="input-soft">
|
||
@foreach(['task' => '📋 Task', 'meeting' => '🤝 Meeting', 'deadline' => '⏰ Deadline', 'posting' => '📸 Posting'] as $val => $label)
|
||
<option value="{{ $val }}" {{ old('event_type') === $val ? 'selected' : '' }}>
|
||
{{ $label }}
|
||
</option>
|
||
@endforeach
|
||
</select>
|
||
</div>
|
||
|
||
{{-- Client --}}
|
||
<div x-data="{
|
||
isNew: false,
|
||
saving: false,
|
||
newName: '', newEmail: '', newPhone: '', newCompany: '',
|
||
errMsg: '',
|
||
onClientChange(e) {
|
||
this.isNew = (e.target.value === '__new__');
|
||
if (!this.isNew) {
|
||
clientId = e.target.value;
|
||
$dispatch('contract-check');
|
||
}
|
||
},
|
||
async saveNewClient() {
|
||
if (!this.newName.trim()) { this.errMsg = 'Name is required.'; return; }
|
||
this.saving = true; this.errMsg = '';
|
||
const fd = new FormData();
|
||
fd.append('name', this.newName);
|
||
fd.append('email', this.newEmail);
|
||
fd.append('phone', this.newPhone);
|
||
fd.append('company', this.newCompany);
|
||
fd.append('_token', document.querySelector('meta[name=csrf-token]').content);
|
||
const res = await fetch('{{ route('clients.quick-store') }}', { method:'POST', body: fd });
|
||
const data = await res.json();
|
||
if (res.ok) {
|
||
// Add new option & select it
|
||
const sel = document.getElementById('client-select');
|
||
const opt = new Option(data.name, data.id, true, true);
|
||
sel.add(opt, sel.options[1]);
|
||
sel.value = data.id;
|
||
sel.dispatchEvent(new Event('change'));
|
||
this.isNew = false;
|
||
this.newName = this.newEmail = this.newPhone = this.newCompany = '';
|
||
} else {
|
||
this.errMsg = data.message ?? 'Could not create client.';
|
||
}
|
||
this.saving = false;
|
||
}
|
||
}">
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">Client</label>
|
||
<select name="client_id" id="client-select" class="input-soft"
|
||
x-model="clientId"
|
||
@change="onClientChange($event); if($event.target.value !== '__new__') checkContract()">
|
||
<option value="">— None —</option>
|
||
<option value="__new__" class="font-semibold text-pink-600">+ Create New Client…</option>
|
||
@foreach($clients as $client)
|
||
<option value="{{ $client->id }}" {{ old('client_id') == $client->id ? 'selected' : '' }}>
|
||
{{ $client->name }}
|
||
</option>
|
||
@endforeach
|
||
</select>
|
||
|
||
{{-- Quick New Client mini-form --}}
|
||
<div x-show="isNew" x-transition
|
||
class="mt-3 bg-purple-50 rounded-2xl p-4 space-y-3 border border-purple-100">
|
||
<p class="text-xs font-bold text-purple-700">🐱 New Client Basic Info</p>
|
||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||
<div>
|
||
<label class="block text-xs font-semibold text-gray-600 mb-1">Name <span class="text-pink-400">*</span></label>
|
||
<input type="text" x-model="newName" class="input-soft text-sm" placeholder="Client / brand name">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-semibold text-gray-600 mb-1">Company</label>
|
||
<input type="text" x-model="newCompany" class="input-soft text-sm" placeholder="Company name">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-semibold text-gray-600 mb-1">Email</label>
|
||
<input type="email" x-model="newEmail" class="input-soft text-sm" placeholder="contact@brand.com">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-semibold text-gray-600 mb-1">Phone</label>
|
||
<input type="text" x-model="newPhone" class="input-soft text-sm" placeholder="+62 …">
|
||
</div>
|
||
</div>
|
||
<p x-show="errMsg" x-text="errMsg" class="text-xs text-red-500"></p>
|
||
<div class="flex gap-2 pt-1">
|
||
<button type="button" @click="saveNewClient()" :disabled="saving"
|
||
class="btn-sakura text-sm px-4 py-2" x-text="saving ? 'Saving…' : '✓ Add & Select'"></button>
|
||
<button type="button" @click="isNew = false; $el.closest('div').querySelector('select').value = ''"
|
||
class="text-sm px-4 py-2 rounded-full border border-pink-200 text-gray-500 hover:bg-pink-50">
|
||
Cancel
|
||
</button>
|
||
</div>
|
||
<p class="text-xs text-purple-400">Status will be set to Active automatically.</p>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Category --}}
|
||
<div class="sm:col-span-2">
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">Category</label>
|
||
<select name="category_id" class="input-soft" x-model="categoryId" @change="checkContract()">
|
||
<option value="">— None —</option>
|
||
@foreach($categoryTree as $parent)
|
||
<option value="{{ $parent->id }}" {{ old('category_id') == $parent->id ? 'selected' : '' }}>
|
||
{{ $parent->icon }} {{ $parent->name }}
|
||
</option>
|
||
@foreach($parent->children as $child)
|
||
<option value="{{ $child->id }}" {{ old('category_id') == $child->id ? 'selected' : '' }}>
|
||
↳ {{ $child->name }}
|
||
</option>
|
||
@endforeach
|
||
@endforeach
|
||
</select>
|
||
</div>
|
||
|
||
{{-- Contract warning --}}
|
||
<div x-show="contractWarning" x-transition
|
||
class="sm:col-span-2 rounded-2xl bg-amber-50 border border-amber-200 px-4 py-3 text-sm"
|
||
style="display:none">
|
||
<div class="font-semibold text-amber-700 mb-1">⚠️ Exclusive Contract Active</div>
|
||
<p class="text-amber-600 text-xs" x-text="contractMessage"></p>
|
||
</div>
|
||
|
||
{{-- Start Date --}}
|
||
<div>
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">
|
||
Start Date <span class="text-pink-400">*</span>
|
||
</label>
|
||
<input type="date" id="start_date" class="input-soft"
|
||
value="{{ old('_start_date') }}" required>
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">Start Time</label>
|
||
<input type="time" id="start_time_input" class="input-soft" value="09:00">
|
||
</div>
|
||
|
||
{{-- End Date --}}
|
||
<div>
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">End Date</label>
|
||
<input type="date" id="end_date" class="input-soft" value="{{ old('_end_date') }}">
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">End Time</label>
|
||
<input type="time" id="end_time_input" class="input-soft" value="18:00">
|
||
</div>
|
||
|
||
{{-- Location --}}
|
||
<div class="sm:col-span-2">
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">Location</label>
|
||
<input type="text" name="location" value="{{ old('location') }}"
|
||
class="input-soft" placeholder="Online / venue address">
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Description --}}
|
||
<div>
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">Description</label>
|
||
<textarea name="description" rows="2" class="input-soft resize-none"
|
||
placeholder="Brief description…">{{ old('description') }}</textarea>
|
||
</div>
|
||
|
||
{{-- Color --}}
|
||
<div x-data="{ color: '{{ old('color', '#FFB7C5') }}' }">
|
||
<label class="block text-sm font-semibold text-gray-700 mb-2">Color</label>
|
||
<input type="hidden" name="color" :value="color">
|
||
<div class="flex items-center gap-3">
|
||
<input type="color" x-model="color"
|
||
class="w-10 h-10 rounded-xl cursor-pointer border-2 border-pink-100 p-0.5 shrink-0">
|
||
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Priority --}}
|
||
<div class="flex items-center gap-2">
|
||
<input type="checkbox" name="is_priority" value="1" id="priority"
|
||
class="w-4 h-4 accent-pink-400" {{ old('is_priority') ? 'checked' : '' }}>
|
||
<label for="priority" class="text-sm text-gray-600 cursor-pointer">⭐ Mark as Priority</label>
|
||
</div>
|
||
|
||
{{-- Notes --}}
|
||
<div>
|
||
<label class="block text-sm font-semibold text-gray-700 mb-1">Notes</label>
|
||
<textarea name="notes" rows="3" class="input-soft resize-none"
|
||
placeholder="Additional notes…">{{ old('notes') }}</textarea>
|
||
</div>
|
||
|
||
{{-- ── Add to Content Board ──────────────────────────────── --}}
|
||
<div x-data="{ addToBoard: {{ old('add_to_content_board') ? 'true' : 'false' }} }">
|
||
<div class="flex items-center gap-2">
|
||
<input type="checkbox" name="add_to_content_board" value="1" id="add_to_content_board"
|
||
class="w-4 h-4 accent-pink-400" x-model="addToBoard">
|
||
<label for="add_to_content_board" class="text-sm text-gray-600 cursor-pointer">
|
||
🗂️ Also add to Content Board as a Drafting card
|
||
</label>
|
||
</div>
|
||
<div x-show="addToBoard" x-transition
|
||
class="mt-3 grid grid-cols-1 sm:grid-cols-2 gap-3 bg-purple-50 rounded-2xl p-4">
|
||
<div>
|
||
<label class="block text-xs font-semibold text-gray-600 mb-1">Platform</label>
|
||
<select name="content_platform" class="input-soft text-sm">
|
||
<option value="instagram" {{ old('content_platform') === 'instagram' ? 'selected' : '' }}>📸 Instagram</option>
|
||
<option value="tiktok" {{ old('content_platform') === 'tiktok' ? 'selected' : '' }}>🎵 TikTok</option>
|
||
<option value="youtube" {{ old('content_platform') === 'youtube' ? 'selected' : '' }}>▶️ YouTube</option>
|
||
<option value="other" {{ old('content_platform') === 'other' ? 'selected' : '' }}>📱 Other</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-semibold text-gray-600 mb-1">Content Type</label>
|
||
<select name="content_type" class="input-soft text-sm">
|
||
<option value="post" {{ old('content_type') === 'post' ? 'selected' : '' }}>Post / Feed</option>
|
||
<option value="reel" {{ old('content_type') === 'reel' ? 'selected' : '' }}>Reel / Short</option>
|
||
<option value="story" {{ old('content_type') === 'story' ? 'selected' : '' }}>Story</option>
|
||
<option value="video" {{ old('content_type') === 'video' ? 'selected' : '' }}>Long Video</option>
|
||
</select>
|
||
</div>
|
||
<p class="sm:col-span-2 text-xs text-purple-500">
|
||
A Drafting card will be created in your Content Board with this event's title and date.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ── Brand Contract ────────────────────────────────────── --}}
|
||
<div x-data="{ createContract: {{ old('create_brand_contract') ? 'true' : 'false' }} }">
|
||
<div class="flex items-center gap-2">
|
||
<input type="checkbox" name="create_brand_contract" value="1" id="create_contract"
|
||
class="w-4 h-4 accent-pink-400" x-model="createContract">
|
||
<label for="create_contract" class="text-sm text-gray-600 cursor-pointer">
|
||
📄 Also create a Brand Contract for this event
|
||
</label>
|
||
</div>
|
||
<div x-show="createContract" x-transition
|
||
class="mt-3 grid grid-cols-1 sm:grid-cols-2 gap-3 bg-pink-50 rounded-2xl p-4">
|
||
<div class="sm:col-span-2">
|
||
<label class="block text-xs font-semibold text-gray-600 mb-1">Contract Title</label>
|
||
<input type="text" name="contract_title" class="input-soft text-sm"
|
||
placeholder="e.g. Exclusive Posting Contract — BrandX"
|
||
value="{{ old('contract_title') }}">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-semibold text-gray-600 mb-1">Contract Start</label>
|
||
<input type="date" name="contract_start_date" class="input-soft text-sm"
|
||
value="{{ old('contract_start_date') }}">
|
||
</div>
|
||
<div>
|
||
<label class="block text-xs font-semibold text-gray-600 mb-1">Contract End</label>
|
||
<input type="date" name="contract_end_date" class="input-soft text-sm"
|
||
value="{{ old('contract_end_date') }}">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex flex-col sm:flex-row gap-3 pt-1">
|
||
<button type="submit" class="btn-sakura flex-1 py-3"
|
||
:class="{ 'opacity-50 cursor-not-allowed': contractWarning }">
|
||
🐾 Schedule It!
|
||
</button>
|
||
<a href="{{ route('schedule.index') }}"
|
||
class="flex-1 py-3 text-center rounded-full border border-pink-200 text-gray-600 hover:bg-pink-50 font-semibold text-sm">
|
||
Cancel
|
||
</a>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
@push('scripts')
|
||
<script>
|
||
document.getElementById('create-event-form').addEventListener('submit', function (e) {
|
||
const startDate = document.getElementById('start_date').value;
|
||
const startTime = document.getElementById('start_time_input').value || '00:00';
|
||
const endDate = document.getElementById('end_date').value;
|
||
const endTime = document.getElementById('end_time_input').value || '00:00';
|
||
|
||
if (!startDate) {
|
||
e.preventDefault();
|
||
alert('Please select a start date.');
|
||
return;
|
||
}
|
||
|
||
document.getElementById('start_time_hidden').value = startDate + 'T' + startTime;
|
||
if (endDate) {
|
||
document.getElementById('end_time_hidden').value = endDate + 'T' + endTime;
|
||
}
|
||
});
|
||
</script>
|
||
@endpush
|
||
@endsection
|