initial commit

This commit is contained in:
I-Fun
2026-04-01 08:04:56 +07:00
commit e09c8a5fa9
111 changed files with 18022 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
@extends('layouts.app')
@section('title', 'Add Rate Card')
@section('page-title', 'Add Service 💰')
@section('content')
<div class="max-w-lg mx-auto">
<div class="cat-card p-4 lg:p-8">
<form action="{{ route('rate-cards.store') }}" method="POST" class="space-y-4">
@csrf
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Service Name <span class="text-pink-400">*</span></label>
<input type="text" name="service_name" value="{{ old('service_name') }}" class="input-soft" required
placeholder="e.g. Instagram Reel (Paid Partnership)">
</div>
<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="Short description of what's included...">{{ old('description') }}</textarea>
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Platform</label>
<select name="platform" class="input-soft">
<option value="general">⭐ General</option>
<option value="instagram">📸 Instagram</option>
<option value="tiktok">🎵 TikTok</option>
<option value="youtube">▶️ YouTube</option>
</select>
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Content Type</label>
<input type="text" name="content_type" value="{{ old('content_type') }}" class="input-soft"
placeholder="Reel, Story, Feed...">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Price <span class="text-pink-400">*</span></label>
<input type="number" name="price" value="{{ old('price') }}" class="input-soft"
min="0" step="100000" required placeholder="0">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Currency</label>
<select name="currency" class="input-soft">
<option value="IDR" selected>IDR</option>
<option value="USD">USD</option>
</select>
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Price Unit</label>
<select name="price_unit" class="input-soft">
<option value="per_content">Per Content</option>
<option value="per_month">Per Month</option>
<option value="per_campaign">Per Campaign</option>
</select>
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Sort Order</label>
<input type="number" name="sort_order" value="{{ old('sort_order', 0) }}" class="input-soft" min="0">
</div>
</div>
<label class="flex items-center gap-3 cursor-pointer py-1">
<input type="checkbox" name="is_negotiable" value="1" {{ old('is_negotiable') ? 'checked' : '' }}
class="w-4 h-4 accent-yellow-400">
<span class="text-sm text-gray-600">Price is negotiable</span>
</label>
<div class="flex flex-col sm:flex-row gap-3 pt-1">
<button type="submit" class="btn-sakura flex-1 py-3">💰 Add Service</button>
<a href="{{ route('rate-cards.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>
@endsection

View File

@@ -0,0 +1,88 @@
@extends('layouts.app')
@section('title', 'Edit Rate Card')
@section('page-title', 'Edit Service 💰')
@section('content')
<div class="max-w-lg mx-auto">
<div class="cat-card p-4 lg:p-8">
<form action="{{ route('rate-cards.update', $rateCard) }}" method="POST" class="space-y-4">
@csrf @method('PUT')
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Service Name</label>
<input type="text" name="service_name" value="{{ old('service_name', $rateCard->service_name) }}"
class="input-soft" required>
</div>
<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">{{ old('description', $rateCard->description) }}</textarea>
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Platform</label>
<select name="platform" class="input-soft">
@foreach(['general','instagram','tiktok','youtube'] as $p)
<option value="{{ $p }}" {{ old('platform', $rateCard->platform) === $p ? 'selected' : '' }}>
{{ ucfirst($p) }}
</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Content Type</label>
<input type="text" name="content_type" value="{{ old('content_type', $rateCard->content_type) }}"
class="input-soft" placeholder="Reel, Story...">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Price</label>
<input type="number" name="price" value="{{ old('price', $rateCard->price) }}"
class="input-soft" min="0" step="100000">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Currency</label>
<select name="currency" class="input-soft">
<option value="IDR" {{ old('currency', $rateCard->currency) === 'IDR' ? 'selected' : '' }}>IDR</option>
<option value="USD" {{ old('currency', $rateCard->currency) === 'USD' ? 'selected' : '' }}>USD</option>
</select>
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Price Unit</label>
<select name="price_unit" class="input-soft">
@foreach(['per_content','per_month','per_campaign'] as $unit)
<option value="{{ $unit }}" {{ old('price_unit', $rateCard->price_unit) === $unit ? 'selected' : '' }}>
{{ str_replace('_', ' ', ucfirst($unit)) }}
</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Sort Order</label>
<input type="number" name="sort_order" value="{{ old('sort_order', $rateCard->sort_order) }}"
class="input-soft" min="0">
</div>
</div>
<div class="flex flex-col gap-2 pt-1">
<label class="flex items-center gap-3 cursor-pointer py-1">
<input type="checkbox" name="is_negotiable" value="1"
{{ old('is_negotiable', $rateCard->is_negotiable) ? 'checked' : '' }}
class="w-4 h-4 accent-yellow-400">
<span class="text-sm text-gray-600">Price is negotiable</span>
</label>
<label class="flex items-center gap-3 cursor-pointer py-1">
<input type="checkbox" name="is_active" value="1"
{{ old('is_active', $rateCard->is_active) ? 'checked' : '' }}
class="w-4 h-4 accent-green-400">
<span class="text-sm text-gray-600">Active (show on public page)</span>
</label>
</div>
<div class="flex flex-col sm:flex-row gap-3 pt-1">
<button type="submit" class="btn-sakura flex-1 py-3">💾 Save Changes</button>
<a href="{{ route('rate-cards.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>
@endsection

View File

@@ -0,0 +1,82 @@
@extends('layouts.app')
@section('title', 'Rate Cards')
@section('page-title', 'Rate Cards 💰')
@section('page-subtitle', 'Manage your service pricing')
@section('content')
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-5">
<a href="{{ route('rate-cards.public') }}" target="_blank"
class="text-sm text-pink-500 hover:underline flex items-center gap-1">
🔗 View Public Page →
</a>
<a href="{{ route('rate-cards.create') }}" class="btn-sakura text-sm shrink-0">+ Add Service</a>
</div>
@php
$grouped = $rateCards->groupBy('platform');
$platformOrder = ['general', 'instagram', 'tiktok', 'youtube'];
@endphp
@foreach($platformOrder as $platform)
@if($grouped->has($platform))
<div class="mb-6">
<h2 class="text-sm font-bold text-gray-700 mb-3 flex items-center gap-2">
<span class="text-lg">{{ $grouped[$platform]->first()->platform_icon }}</span>
{{ ucfirst($platform) }}
<span class="text-xs text-gray-400 font-normal">({{ $grouped[$platform]->count() }})</span>
</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3">
@foreach($grouped[$platform] as $card)
<div class="cat-card p-4 {{ !$card->is_active ? 'opacity-50' : '' }}">
<div class="flex justify-between items-start gap-2 mb-2">
<div class="min-w-0">
<h3 class="font-bold text-gray-800 text-sm leading-tight">{{ $card->service_name }}</h3>
@if($card->content_type)
<span class="text-xs bg-pink-50 text-pink-600 px-2 py-0.5 rounded-full inline-block mt-1">{{ $card->content_type }}</span>
@endif
</div>
<span class="text-xs px-2 py-1 rounded-full shrink-0
{{ $card->is_active ? 'bg-green-100 text-green-600' : 'bg-gray-100 text-gray-400' }}">
{{ $card->is_active ? 'Active' : 'Hidden' }}
</span>
</div>
@if($card->description)
<p class="text-xs text-gray-500 mb-2 line-clamp-2">{{ $card->description }}</p>
@endif
<div class="text-xl font-extrabold text-pink-500 mb-0.5">{{ $card->formatted_price }}</div>
<div class="text-xs text-gray-400 mb-3">
{{ str_replace('_', ' ', $card->price_unit) }}
@if($card->is_negotiable) <span class="text-amber-500 ml-1">· Negotiable</span> @endif
</div>
<div class="flex gap-2 pt-3 border-t border-pink-50">
<a href="{{ route('rate-cards.edit', $card) }}"
class="flex-1 text-center text-xs py-2 rounded-full border border-pink-200 text-gray-600 hover:bg-pink-50 font-medium">
Edit
</a>
<form action="{{ route('rate-cards.destroy', $card) }}" method="POST"
onsubmit="return confirm('Delete this entry?')">
@csrf @method('DELETE')
<button class="text-xs py-2 px-4 rounded-full border border-red-100 text-red-400 hover:bg-red-50">
Delete
</button>
</form>
</div>
</div>
@endforeach
</div>
</div>
@endif
@endforeach
@if($rateCards->isEmpty())
<div class="text-center py-20 text-gray-400">
<span class="text-5xl block mb-3">💰</span>
<p class="text-sm">No rate cards yet.</p>
<a href="{{ route('rate-cards.create') }}" class="btn-sakura mt-4 inline-block">Add your first service!</a>
</div>
@endif
@endsection

View File

@@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rate Card — KOL Manager</title>
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800;900&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Nunito', sans-serif; background: #FFF8F0; color: #374151; padding: 40px 20px; }
.container { max-width: 800px; margin: 0 auto; }
.header { text-align: center; margin-bottom: 48px; }
.logo { font-size: 48px; margin-bottom: 12px; }
.title { font-size: 32px; font-weight: 900; color: #FFB7C5; }
.subtitle { color: #9CA3AF; margin-top: 6px; font-size: 14px; }
.platform-section { margin-bottom: 32px; }
.platform-title { font-size: 18px; font-weight: 800; color: #374151; margin-bottom: 12px; display: flex; align-items: center; gap: 8px; }
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px; }
.card { background: white; border-radius: 24px; padding: 20px; border: 1px solid #FFE4EC; box-shadow: 0 2px 8px rgba(255,183,197,0.15); }
.service { font-weight: 700; color: #1F2937; margin-bottom: 6px; }
.type { display: inline-block; background: #FFF0F5; color: #FFB7C5; font-size: 11px; font-weight: 600; padding: 2px 10px; border-radius: 20px; margin-bottom: 8px; }
.desc { font-size: 12px; color: #9CA3AF; margin-bottom: 12px; line-height: 1.5; }
.price { font-size: 22px; font-weight: 900; color: #FFB7C5; }
.price-meta { font-size: 11px; color: #D1D5DB; margin-top: 2px; }
.negotiable { font-size: 11px; color: #F59E0B; font-weight: 600; }
.footer { text-align: center; margin-top: 60px; color: #D1D5DB; font-size: 12px; }
@media print { body { background: white; } .card { break-inside: avoid; } }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="logo">🐱</div>
<div class="title">Rate Card</div>
<div class="subtitle">Services & Pricing · {{ now()->format('Y') }}</div>
</div>
@forelse($rateCards as $platform => $cards)
<div class="platform-section">
<div class="platform-title">
<span>{{ $cards->first()->platform_icon }}</span>
{{ ucfirst($platform) }}
</div>
<div class="cards">
@foreach($cards as $card)
<div class="card">
@if($card->content_type)
<div class="type">{{ $card->content_type }}</div>
@endif
<div class="service">{{ $card->service_name }}</div>
@if($card->description)
<div class="desc">{{ $card->description }}</div>
@endif
<div class="price">{{ $card->formatted_price }}</div>
<div class="price-meta">{{ str_replace('_', ' ', $card->price_unit) }}</div>
@if($card->is_negotiable)
<div class="negotiable">✦ Negotiable</div>
@endif
</div>
@endforeach
</div>
</div>
@empty
<p style="text-align:center; color:#9CA3AF; padding: 60px 0;">No rate cards published yet.</p>
@endforelse
<div class="footer">
Generated by KOL Manager · Prices may vary. Contact for custom packages. 🐾
</div>
</div>
</body>
</html>