Files
hub/app/Http/Controllers/Seller/BrandManagerSettingsController.php
kelly c7d6ee5e21 feat: multiple UI/UX improvements and case-insensitive search
- Refactor New Quote page to enterprise data-entry layout (2-column, dense)
- Add Payment Terms dropdown (COD, NET 15, NET 30, NET 60)
- Fix sidebar menu active states and route names
- Fix brand filter badge visibility on brands page
- Remove company_name references (use business instead)
- Polish Promotions page layout
- Fix double-click issue on sidebar menu collapse
- Make all searches case-insensitive (like -> ilike for PostgreSQL)
2025-12-14 15:36:00 -07:00

320 lines
12 KiB
PHP

<?php
namespace App\Http\Controllers\Seller;
use App\Http\Controllers\Controller;
use App\Models\Brand;
use App\Models\Business;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;
class BrandManagerSettingsController extends Controller
{
/**
* Display the brand managers list.
*/
public function index(Business $business, Request $request)
{
$this->authorizeOwnerAccess($business);
// Get all users with contact_type = 'brand_manager' for this business
$query = $business->users()
->wherePivot('contact_type', 'brand_manager')
->with(['brands' => fn ($q) => $q->where('business_id', $business->id)]);
// Search
if ($request->filled('search')) {
$search = $request->search;
$query->where(function ($q) use ($search) {
$q->where('first_name', 'ilike', "%{$search}%")
->orWhere('last_name', 'ilike', "%{$search}%")
->orWhere('email', 'ilike', "%{$search}%");
});
}
$brandManagers = $query->paginate(15);
// Get all brands for this business (for the add/edit modal)
$brands = $business->brands()->orderBy('name')->get();
return view('seller.settings.brand-managers', compact('business', 'brandManagers', 'brands'));
}
/**
* Store a new brand manager.
*/
public function store(Business $business, Request $request)
{
$this->authorizeOwnerAccess($business);
$validated = $request->validate([
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'email' => 'required|email|max:255',
'phone' => 'nullable|string|max:20',
'brands' => 'required|array|min:1',
'brands.*' => 'exists:brands,id',
'primary_brand_id' => 'nullable|exists:brands,id',
], [
'brands.required' => 'Please select at least one brand.',
'brands.min' => 'Please select at least one brand.',
]);
// Verify all selected brands belong to this business
$validBrandIds = $business->brands()->whereIn('id', $validated['brands'])->pluck('id')->toArray();
if (count($validBrandIds) !== count($validated['brands'])) {
return back()->withErrors(['brands' => 'Invalid brand selection.']);
}
DB::beginTransaction();
try {
// Check if user already exists
$user = User::where('email', $validated['email'])->first();
if ($user) {
// Check if user is already a brand manager for this business
$existingPivot = $user->businesses()
->where('business_id', $business->id)
->wherePivot('contact_type', 'brand_manager')
->first();
if ($existingPivot) {
return back()->withErrors(['email' => 'This user is already a brand manager for this business.']);
}
// Update user details
$user->update([
'first_name' => $validated['first_name'],
'last_name' => $validated['last_name'],
'phone' => $validated['phone'] ?? $user->phone,
]);
} else {
// Create new user
$user = User::create([
'first_name' => $validated['first_name'],
'last_name' => $validated['last_name'],
'email' => $validated['email'],
'phone' => $validated['phone'],
'password' => Hash::make(\Str::random(32)), // Random password, user will need to reset
'user_type' => 'seller',
'status' => 'active',
]);
}
// Attach user to business with brand_manager contact type
if (! $user->businesses()->where('business_id', $business->id)->exists()) {
$user->businesses()->attach($business->id, [
'contact_type' => 'brand_manager',
'is_primary' => true,
'permissions' => json_encode([
'view_products',
'view_sales',
'view_orders',
'view_inventory',
'view_promotions',
'view_conversations',
'view_buyers',
'view_analytics',
]),
]);
} else {
// Update existing pivot to brand_manager
$user->businesses()->updateExistingPivot($business->id, [
'contact_type' => 'brand_manager',
]);
}
// Attach brands to user
$primaryBrandId = $validated['primary_brand_id'] ?? $validated['brands'][0];
foreach ($validated['brands'] as $brandId) {
if (! $user->brands()->where('brand_id', $brandId)->exists()) {
$user->brands()->attach($brandId, [
'role' => 'manager',
'is_primary' => $brandId == $primaryBrandId,
'permissions' => json_encode([
'view_sales',
'view_orders',
'view_products',
'view_inventory',
'view_promotions',
'view_conversations',
'view_buyers',
'view_analytics',
]),
]);
}
}
DB::commit();
// TODO: Send invitation email to user with password reset link
return redirect()
->route('seller.business.settings.brand-managers.index', $business->slug)
->with('success', "Brand manager {$user->name} has been added successfully.");
} catch (\Exception $e) {
DB::rollBack();
report($e);
return back()->withErrors(['error' => 'Failed to create brand manager. Please try again.']);
}
}
/**
* Update a brand manager's details and brand assignments.
*/
public function update(Business $business, User $user, Request $request)
{
$this->authorizeOwnerAccess($business);
// Verify user is a brand manager for this business
$isBrandManager = $user->businesses()
->where('business_id', $business->id)
->wherePivot('contact_type', 'brand_manager')
->exists();
if (! $isBrandManager) {
abort(404, 'Brand manager not found.');
}
$validated = $request->validate([
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'phone' => 'nullable|string|max:20',
'brands' => 'required|array|min:1',
'brands.*' => 'exists:brands,id',
'primary_brand_id' => 'nullable|exists:brands,id',
], [
'brands.required' => 'Please select at least one brand.',
'brands.min' => 'Please select at least one brand.',
]);
// Verify all selected brands belong to this business
$validBrandIds = $business->brands()->whereIn('id', $validated['brands'])->pluck('id')->toArray();
if (count($validBrandIds) !== count($validated['brands'])) {
return back()->withErrors(['brands' => 'Invalid brand selection.']);
}
DB::beginTransaction();
try {
// Update user details
$user->update([
'first_name' => $validated['first_name'],
'last_name' => $validated['last_name'],
'phone' => $validated['phone'],
]);
// Sync brands - remove old, add new
$currentBrandIds = $user->brands()
->where('business_id', $business->id)
->pluck('brands.id')
->toArray();
$newBrandIds = $validated['brands'];
$primaryBrandId = $validated['primary_brand_id'] ?? $newBrandIds[0];
// Remove brands that are no longer selected
$brandsToRemove = array_diff($currentBrandIds, $newBrandIds);
if (! empty($brandsToRemove)) {
$user->brands()->detach($brandsToRemove);
}
// Add new brands or update existing
foreach ($newBrandIds as $brandId) {
if ($user->brands()->where('brand_id', $brandId)->exists()) {
// Update is_primary flag
$user->brands()->updateExistingPivot($brandId, [
'is_primary' => $brandId == $primaryBrandId,
]);
} else {
// Add new brand
$user->brands()->attach($brandId, [
'role' => 'manager',
'is_primary' => $brandId == $primaryBrandId,
'permissions' => json_encode([
'view_sales',
'view_orders',
'view_products',
'view_inventory',
'view_promotions',
'view_conversations',
'view_buyers',
'view_analytics',
]),
]);
}
}
DB::commit();
return redirect()
->route('seller.business.settings.brand-managers.index', $business->slug)
->with('success', "Brand manager {$user->name} has been updated successfully.");
} catch (\Exception $e) {
DB::rollBack();
report($e);
return back()->withErrors(['error' => 'Failed to update brand manager. Please try again.']);
}
}
/**
* Remove a brand manager from the business.
*/
public function destroy(Business $business, User $user, Request $request)
{
$this->authorizeOwnerAccess($business);
// Verify user is a brand manager for this business
$isBrandManager = $user->businesses()
->where('business_id', $business->id)
->wherePivot('contact_type', 'brand_manager')
->exists();
if (! $isBrandManager) {
abort(404, 'Brand manager not found.');
}
DB::beginTransaction();
try {
// Remove all brand assignments for this business
$businessBrandIds = $business->brands()->pluck('id')->toArray();
$user->brands()->detach($businessBrandIds);
// Remove from business or update contact_type
$user->businesses()->detach($business->id);
DB::commit();
return redirect()
->route('seller.business.settings.brand-managers.index', $business->slug)
->with('success', "Brand manager {$user->name} has been removed.");
} catch (\Exception $e) {
DB::rollBack();
report($e);
return back()->withErrors(['error' => 'Failed to remove brand manager. Please try again.']);
}
}
/**
* Authorize that current user is business owner or super admin.
*/
private function authorizeOwnerAccess(Business $business): void
{
$user = auth()->user();
$isOwner = $business->owner_user_id === $user->id;
$isSuperAdmin = $user->user_type === 'admin';
if (! $isOwner && ! $isSuperAdmin) {
abort(403, 'Only business owners and administrators can manage brand managers.');
}
}
}