Files
Kol-Manager/resources/views/schedule/create.blade.php

452 lines
27 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@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="btn-sakura text-sm px-5 py-2">
← 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', [], false) }}')" 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" x-data="{
isNew: false,
saving: false,
newName: '', newEmail: '', newPhone: '', newCompany: '',
errMsg: '',
isNewCat: false,
savingCat: false,
newCatName: '',
catErrMsg: '',
onClientChange(e) {
this.isNew = (e.target.value === '__new__');
if (!this.isNew) {
this.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);
try {
const res = await fetch('{{ route('clients.quick-store', [], false) }}', {
method:'POST',
body: fd,
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});
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.';
}
} catch (err) {
this.errMsg = 'An unexpected error occurred.';
} finally {
this.saving = false;
}
},
onCategoryChange(e) {
this.isNewCat = (e.target.value === '__new__');
if (!this.isNewCat) {
this.categoryId = e.target.value;
this.checkContract();
}
},
async saveNewCategory() {
if (!this.newCatName.trim()) { this.catErrMsg = 'Category name is required.'; return; }
this.savingCat = true; this.catErrMsg = '';
const fd = new FormData();
fd.append('name', this.newCatName);
fd.append('_token', document.querySelector('meta[name=csrf-token]').content);
try {
const res = await fetch('{{ route('client-categories.quick-store', [], false) }}', {
method:'POST',
body: fd,
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});
const data = await res.json();
if (res.ok) {
const sel = document.getElementById('category-select');
const opt = new Option(data.icon + ' ' + data.name, data.id, true, true);
sel.add(opt, sel.options[1]);
sel.value = data.id;
sel.dispatchEvent(new Event('change'));
this.isNewCat = false;
this.newCatName = '';
} else {
this.catErrMsg = data.message || 'Could not create category.';
}
} catch (err) {
this.catErrMsg = 'An unexpected error occurred.';
} finally {
this.savingCat = false;
}
}
}">
{{-- 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>
<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>
</div>
{{-- Quick New Client mini-form --}}
<div x-show="isNew" x-transition style="display: none;"
class="sm:col-span-2 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; document.getElementById('client-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>
{{-- 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" id="category-select" class="input-soft" x-model="categoryId"
@change="onCategoryChange($event)">
<option value="">— None —</option>
<option value="__new__" class="font-semibold text-pink-600">+ Create New Category…</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' : '' }}>
&nbsp;&nbsp;↳ {{ $child->name }}
</option>
@endforeach
@endforeach
</select>
</div>
{{-- Quick New Category mini-form --}}
<div x-show="isNewCat" x-transition style="display: none;"
class="sm:col-span-2 bg-pink-50 rounded-2xl p-4 space-y-3 border border-pink-100">
<p class="text-xs font-bold text-pink-700">🏷️ New Category</p>
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Category Name <span
class="text-pink-400">*</span></label>
<input type="text" x-model="newCatName" class="input-soft text-sm" placeholder="e.g. Susu UHT">
</div>
<p x-show="catErrMsg" x-text="catErrMsg" class="text-xs text-red-500"></p>
<div class="flex gap-2 pt-1">
<button type="button" @click="saveNewCategory()" :disabled="savingCat"
class="btn-sakura text-sm px-4 py-2"
x-text="savingCat ? 'Saving…' : '✓ Add & Select'"></button>
<button type="button"
@click="isNewCat = false; document.getElementById('category-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>
</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
@change="checkContract()">
</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 }" :disabled="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>
function contractCheck(checkUrl) {
return {
categoryId: '',
clientId: '',
contractWarning: false,
contractMessage: '',
async checkContract() {
if (!this.categoryId) { this.contractWarning = false; return; }
let dateVal = '';
const startDateEl = document.getElementById('start_date');
if (startDateEl && startDateEl.value) {
dateVal = startDateEl.value;
}
if (!dateVal) {
this.contractWarning = false;
return;
}
const params = new URLSearchParams({
category_id: this.categoryId,
client_id: this.clientId || '',
date: dateVal
});
try {
const res = await fetch(checkUrl + '?' + params);
if (!res.ok) throw new Error('Network error');
const data = await res.json();
if (data && data.title) {
this.contractWarning = true;
this.contractMessage = `"${data.title}" — ${data.client_name} holds exclusive rights in the ${data.category} category until ${data.end_date} (${data.days_left} days left).`;
} else {
this.contractWarning = false;
this.contractMessage = '';
}
} catch (e) {
this.contractWarning = false;
this.contractMessage = '';
}
}
};
}
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