Add contract management and invoice settings pages

- Created a new Blade view for managing brand contracts with forms for adding and editing contracts, including client and category selection.
- Implemented success message notifications for contract actions.
- Added a new Blade view for invoice settings, allowing customization of invoice number format, header branding, and default values for new invoices.
- Introduced a new PDF view for generating rate cards with customizable styles based on user profile settings.
- Developed a profile management page for rate cards, enabling users to update their identity, appearance, and visibility settings.
This commit is contained in:
I-Fun
2026-04-01 21:47:34 +07:00
parent d3c35ad730
commit 22f03ccca7
48 changed files with 2415 additions and 296 deletions

View File

@@ -0,0 +1,213 @@
@extends('layouts.app')
@section('title', 'Categories')
@section('page-title', '🏷️ Category Management')
@section('page-subtitle', 'Organise clients, schedules & content by category')
@section('content')
<div class="max-w-4xl mx-auto space-y-5">
@if(session('success'))
<div x-data="{ show: true }" x-show="show" x-init="setTimeout(() => show = false, 4000)"
class="flex items-center justify-between gap-3 bg-green-50 border border-green-200 rounded-2xl px-4 py-3 text-sm text-green-700">
<span>{{ session('success') }}</span>
<button @click="show = false" class="text-green-500 hover:text-green-700 text-lg leading-none">✕</button>
</div>
@endif
{{-- Add form --}}
<div class="cat-card overflow-hidden">
<div class="flex items-center gap-3 px-5 py-4 border-b border-pink-50">
<span class="text-xl">➕</span>
<h2 class="font-bold text-gray-700">Add New Category</h2>
</div>
<form action="{{ route('client-categories.store') }}" method="POST"
class="p-5 grid grid-cols-2 sm:grid-cols-4 gap-3 items-end">
@csrf
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Name <span class="text-pink-400">*</span></label>
<input type="text" name="name" required maxlength="100"
placeholder="e.g. Energy Drinks"
class="input-soft" value="{{ old('name') }}">
</div>
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Parent (optional)</label>
<select name="parent_id" class="input-soft">
<option value="">— Root category —</option>
@foreach($parents as $p)
<option value="{{ $p->id }}" {{ old('parent_id') == $p->id ? 'selected' : '' }}>
{{ $p->icon }} {{ $p->name }}
</option>
@endforeach
</select>
</div>
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Icon (emoji)</label>
<input type="text" name="icon" maxlength="10" placeholder="🏷️"
class="input-soft" value="{{ old('icon') }}">
</div>
<div class="flex items-end gap-2">
<div class="flex-1">
<label class="block text-xs font-semibold text-gray-600 mb-1">Color</label>
<input type="color" name="color" value="{{ old('color', '#FFB7C5') }}"
class="w-full h-[42px] rounded-2xl border border-pink-200 cursor-pointer p-1 bg-white">
</div>
<button type="submit" class="btn-sakura px-4 py-2.5 shrink-0 text-sm">Add</button>
</div>
</form>
</div>
{{-- List --}}
<div class="cat-card overflow-hidden">
<div class="flex items-center gap-3 px-5 py-4 border-b border-pink-50">
<span class="text-xl">🗂️</span>
<h2 class="font-bold text-gray-700">All Categories</h2>
<span class="ml-auto text-xs bg-pink-100 text-pink-600 font-semibold px-2.5 py-0.5 rounded-full">
{{ $categories->count() }} total
</span>
</div>
@php $roots = $categories->whereNull('parent_id'); @endphp
@forelse($roots as $root)
<div x-data="{ editing: false }" class="border-b border-pink-50 last:border-0">
{{-- Root row --}}
<div class="flex items-center gap-3 px-5 py-3 hover:bg-pink-50/40 transition-colors">
<span class="text-xl w-7 text-center shrink-0">{{ $root->icon ?: '🏷️' }}</span>
@if($root->color)
<span class="w-3 h-3 rounded-full shrink-0" style="background:{{ $root->color }}"></span>
@endif
<div class="flex-1 min-w-0">
<div class="font-semibold text-gray-700 text-sm">{{ $root->name }}</div>
<div class="text-xs text-gray-400">{{ $root->children->count() }} sub · {{ $root->clients_count }} client(s)</div>
</div>
<div class="flex gap-2 shrink-0">
<button @click="editing = !editing"
class="text-xs px-3 py-1.5 rounded-full border border-blue-200 text-blue-500 hover:bg-blue-50">
✏️ Edit
</button>
@unless($root->is_system)
<form action="{{ route('client-categories.destroy', $root) }}" method="POST"
onsubmit="return confirm('Remove this category? Its children will be promoted.')">
@csrf @method('DELETE')
<button class="text-xs px-3 py-1.5 rounded-full border border-red-100 text-red-400 hover:bg-red-50">
🗑️
</button>
</form>
@endunless
</div>
</div>
{{-- Edit form --}}
<div x-show="editing" x-transition style="display:none"
class="px-5 py-4 bg-pink-50/30 border-t border-pink-50">
<form action="{{ route('client-categories.update', $root) }}" method="POST"
class="grid grid-cols-2 sm:grid-cols-4 gap-3 items-end">
@csrf @method('PUT')
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Name</label>
<input type="text" name="name" required value="{{ $root->name }}" class="input-soft">
</div>
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Parent</label>
<select name="parent_id" class="input-soft">
<option value="">— Root —</option>
@foreach($parents as $p)
@if($p->id !== $root->id)
<option value="{{ $p->id }}" {{ $root->parent_id == $p->id ? 'selected' : '' }}>
{{ $p->icon }} {{ $p->name }}
</option>
@endif
@endforeach
</select>
</div>
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Icon</label>
<input type="text" name="icon" value="{{ $root->icon }}" maxlength="10" class="input-soft">
</div>
<div class="flex items-end gap-2">
<div class="flex-1">
<label class="block text-xs font-semibold text-gray-600 mb-1">Color</label>
<input type="color" name="color" value="{{ $root->color ?: '#FFB7C5' }}"
class="w-full h-[42px] rounded-2xl border border-pink-200 cursor-pointer p-1 bg-white">
</div>
<button type="submit" class="btn-sakura px-3 py-2.5 text-sm shrink-0">Save</button>
</div>
</form>
</div>
{{-- Children --}}
@foreach($root->children as $child)
<div x-data="{ editingC: false }">
<div class="flex items-center gap-3 px-5 py-2.5 pl-12 border-t border-pink-50/60 hover:bg-pink-50/20 transition-colors">
<span class="text-base w-6 text-center shrink-0">{{ $child->icon ?: '↳' }}</span>
@if($child->color)
<span class="w-2.5 h-2.5 rounded-full shrink-0" style="background:{{ $child->color }}"></span>
@endif
<div class="flex-1 min-w-0">
<div class="text-sm font-medium text-gray-600">↳ {{ $child->name }}</div>
<div class="text-xs text-gray-400">{{ $child->clients_count }} client(s)</div>
</div>
<div class="flex gap-2 shrink-0">
<button @click="editingC = !editingC"
class="text-xs px-2.5 py-1 rounded-full border border-blue-200 text-blue-500 hover:bg-blue-50">
✏️
</button>
@unless($child->is_system)
<form action="{{ route('client-categories.destroy', $child) }}" method="POST"
onsubmit="return confirm('Remove subcategory?')">
@csrf @method('DELETE')
<button class="text-xs px-2.5 py-1 rounded-full border border-red-100 text-red-400 hover:bg-red-50">
🗑️
</button>
</form>
@endunless
</div>
</div>
<div x-show="editingC" x-transition style="display:none"
class="px-5 py-4 pl-12 bg-pink-50/20 border-t border-pink-50/60">
<form action="{{ route('client-categories.update', $child) }}" method="POST"
class="grid grid-cols-2 sm:grid-cols-4 gap-3 items-end">
@csrf @method('PUT')
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Name</label>
<input type="text" name="name" required value="{{ $child->name }}" class="input-soft">
</div>
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Parent</label>
<select name="parent_id" class="input-soft">
<option value="">— Root —</option>
@foreach($parents as $p)
@if($p->id !== $child->id)
<option value="{{ $p->id }}" {{ $child->parent_id == $p->id ? 'selected' : '' }}>
{{ $p->icon }} {{ $p->name }}
</option>
@endif
@endforeach
</select>
</div>
<div>
<label class="block text-xs font-semibold text-gray-600 mb-1">Icon</label>
<input type="text" name="icon" value="{{ $child->icon }}" maxlength="10" class="input-soft">
</div>
<div class="flex items-end gap-2">
<div class="flex-1">
<label class="block text-xs font-semibold text-gray-600 mb-1">Color</label>
<input type="color" name="color" value="{{ $child->color ?: '#FFB7C5' }}"
class="w-full h-[42px] rounded-2xl border border-pink-200 cursor-pointer p-1 bg-white">
</div>
<button type="submit" class="btn-sakura px-3 py-2.5 text-sm shrink-0">Save</button>
</div>
</form>
</div>
</div>
@endforeach
</div>
@empty
<div class="text-center py-14 text-gray-400">
<div class="text-4xl mb-2">🏷️</div>
<p class="text-sm">No categories yet. Add your first one above.</p>
</div>
@endforelse
</div>
</div>
@endsection