390 lines
15 KiB
PHP
390 lines
15 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Tenant;
|
|
use App\Models\User;
|
|
use App\Models\ClubSocialLink;
|
|
use App\Models\ClubBankAccount;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Facades\Validator;
|
|
|
|
class ClubApiController extends Controller
|
|
{
|
|
/**
|
|
* Get all users for user picker.
|
|
*/
|
|
public function getUsers(Request $request)
|
|
{
|
|
$users = User::select('id', 'full_name', 'email', 'mobile', 'profile_picture')
|
|
->orderBy('full_name')
|
|
->get()
|
|
->map(function ($user) {
|
|
return [
|
|
'id' => $user->id,
|
|
'full_name' => $user->full_name,
|
|
'email' => $user->email,
|
|
'mobile' => $user->mobile_formatted,
|
|
'profile_picture' => $user->profile_picture
|
|
? asset('storage/' . $user->profile_picture)
|
|
: null,
|
|
];
|
|
});
|
|
|
|
return response()->json($users);
|
|
}
|
|
|
|
/**
|
|
* Get club data for editing.
|
|
*/
|
|
public function getClub($id)
|
|
{
|
|
$club = Tenant::with(['owner', 'socialLinks', 'bankAccounts'])
|
|
->findOrFail($id);
|
|
|
|
return response()->json([
|
|
'id' => $club->id,
|
|
'owner_user_id' => $club->owner_user_id,
|
|
'club_name' => $club->club_name,
|
|
'slug' => $club->slug,
|
|
'logo' => $club->logo,
|
|
'cover_image' => $club->cover_image,
|
|
'slogan' => $club->slogan,
|
|
'description' => $club->description,
|
|
'established_date' => $club->established_date,
|
|
'commercial_reg_number' => $club->commercial_reg_number,
|
|
'vat_reg_number' => $club->vat_reg_number,
|
|
'vat_percentage' => $club->vat_percentage,
|
|
'email' => $club->email,
|
|
'phone' => $club->phone,
|
|
'currency' => $club->currency,
|
|
'timezone' => $club->timezone,
|
|
'country' => $club->country,
|
|
'address' => $club->address,
|
|
'gps_lat' => $club->gps_lat,
|
|
'gps_long' => $club->gps_long,
|
|
'enrollment_fee' => $club->enrollment_fee,
|
|
'status' => $club->status ?? 'active',
|
|
'public_profile_enabled' => $club->public_profile_enabled ?? true,
|
|
'owner' => $club->owner ? [
|
|
'id' => $club->owner->id,
|
|
'full_name' => $club->owner->full_name,
|
|
'email' => $club->owner->email,
|
|
'mobile' => $club->owner->mobile_formatted,
|
|
'profile_picture' => $club->owner->profile_picture
|
|
? asset('storage/' . $club->owner->profile_picture)
|
|
: null,
|
|
] : null,
|
|
'social_links' => $club->socialLinks->map(function ($link) {
|
|
return [
|
|
'platform' => $link->platform,
|
|
'url' => $link->url,
|
|
];
|
|
}),
|
|
'bank_accounts' => $club->bankAccounts->map(function ($account) {
|
|
return [
|
|
'bank_name' => $account->bank_name,
|
|
'account_name' => $account->account_name,
|
|
'account_number' => $account->account_number,
|
|
'iban' => $account->iban,
|
|
'swift_code' => $account->swift_code,
|
|
'benefitpay_account' => $account->benefitpay_account ?? '',
|
|
];
|
|
}),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Check if slug is available.
|
|
*/
|
|
public function checkSlug(Request $request)
|
|
{
|
|
$slug = $request->input('slug');
|
|
$clubId = $request->input('club_id');
|
|
|
|
$query = Tenant::where('slug', $slug);
|
|
|
|
if ($clubId) {
|
|
$query->where('id', '!=', $clubId);
|
|
}
|
|
|
|
$exists = $query->exists();
|
|
|
|
return response()->json([
|
|
'available' => !$exists,
|
|
'message' => $exists ? 'This slug is already taken' : 'Slug is available'
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Store a new club.
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
$validator = Validator::make($request->all(), [
|
|
'owner_user_id' => 'required|exists:users,id',
|
|
'club_name' => 'required|string|max:255',
|
|
'slug' => 'required|string|max:255|unique:tenants,slug',
|
|
'slogan' => 'nullable|string|max:100',
|
|
'description' => 'nullable|string|max:1000',
|
|
'established_date' => 'nullable|date',
|
|
'commercial_reg_number' => 'nullable|string|max:100',
|
|
'vat_reg_number' => 'nullable|string|max:100',
|
|
'vat_percentage' => 'nullable|numeric|min:0|max:100',
|
|
'email' => 'nullable|email',
|
|
'phone_code' => 'nullable|string',
|
|
'phone_number' => 'nullable|string',
|
|
'currency' => 'nullable|string|max:3',
|
|
'timezone' => 'nullable|string',
|
|
'country' => 'nullable|string',
|
|
'address' => 'nullable|string',
|
|
'gps_lat' => 'nullable|numeric|between:-90,90',
|
|
'gps_long' => 'nullable|numeric|between:-180,180',
|
|
'enrollment_fee' => 'nullable|numeric|min:0',
|
|
'club_status' => 'nullable|in:active,inactive,pending',
|
|
'public_profile_enabled' => 'nullable|boolean',
|
|
'logo' => 'nullable',
|
|
'cover_image' => 'nullable',
|
|
'social_links' => 'nullable|array',
|
|
'social_links.*.platform' => 'required_with:social_links.*.url|string',
|
|
'social_links.*.url' => 'required_with:social_links.*.platform|url',
|
|
'bank_accounts' => 'nullable|array',
|
|
'bank_accounts.*.bank_name' => 'required_with:bank_accounts|string',
|
|
'bank_accounts.*.account_name' => 'required_with:bank_accounts|string',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Validation failed',
|
|
'errors' => $validator->errors()
|
|
], 422);
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
$data = $validator->validated();
|
|
|
|
// Handle phone as JSON
|
|
if ($request->filled('phone_code') && $request->filled('phone_number')) {
|
|
$data['phone'] = [
|
|
'code' => $request->phone_code,
|
|
'number' => $request->phone_number,
|
|
];
|
|
}
|
|
|
|
// Handle logo upload
|
|
if ($request->filled('logo') && str_starts_with($request->logo, 'data:image')) {
|
|
$data['logo'] = $this->handleBase64Image($request->logo, 'clubs/logos', 'logo_' . time());
|
|
}
|
|
|
|
// Handle cover image upload
|
|
if ($request->filled('cover_image') && str_starts_with($request->cover_image, 'data:image')) {
|
|
$data['cover_image'] = $this->handleBase64Image($request->cover_image, 'clubs/covers', 'cover_' . time());
|
|
}
|
|
|
|
// Set status
|
|
$data['status'] = $request->input('club_status', 'active');
|
|
$data['public_profile_enabled'] = $request->boolean('public_profile_enabled', true);
|
|
|
|
// Create club
|
|
$club = Tenant::create($data);
|
|
|
|
// Handle social links
|
|
if ($request->has('social_links')) {
|
|
foreach ($request->social_links as $index => $link) {
|
|
if (!empty($link['platform']) && !empty($link['url'])) {
|
|
ClubSocialLink::create([
|
|
'tenant_id' => $club->id,
|
|
'platform' => $link['platform'],
|
|
'url' => $link['url'],
|
|
'display_order' => $index,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle bank accounts
|
|
if ($request->has('bank_accounts')) {
|
|
foreach ($request->bank_accounts as $account) {
|
|
if (!empty($account['bank_name']) && !empty($account['account_name'])) {
|
|
ClubBankAccount::create([
|
|
'tenant_id' => $club->id,
|
|
'bank_name' => $account['bank_name'],
|
|
'account_name' => $account['account_name'],
|
|
'account_number' => $account['account_number'] ?? null,
|
|
'iban' => $account['iban'] ?? null,
|
|
'swift_code' => $account['swift_code'] ?? null,
|
|
'benefitpay_account' => $account['benefitpay_account'] ?? null,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Assign club-admin role to owner
|
|
$owner = User::find($data['owner_user_id']);
|
|
$owner->assignRole('club-admin', $club->id);
|
|
|
|
DB::commit();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Club created successfully!',
|
|
'club' => $club
|
|
]);
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Failed to create club: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update an existing club.
|
|
*/
|
|
public function update(Request $request, $id)
|
|
{
|
|
$club = Tenant::findOrFail($id);
|
|
|
|
$validator = Validator::make($request->all(), [
|
|
'owner_user_id' => 'required|exists:users,id',
|
|
'club_name' => 'required|string|max:255',
|
|
'slug' => 'required|string|max:255|unique:tenants,slug,' . $id,
|
|
'slogan' => 'nullable|string|max:100',
|
|
'description' => 'nullable|string|max:1000',
|
|
'established_date' => 'nullable|date',
|
|
'commercial_reg_number' => 'nullable|string|max:100',
|
|
'vat_reg_number' => 'nullable|string|max:100',
|
|
'vat_percentage' => 'nullable|numeric|min:0|max:100',
|
|
'email' => 'nullable|email',
|
|
'phone_code' => 'nullable|string',
|
|
'phone_number' => 'nullable|string',
|
|
'currency' => 'nullable|string|max:3',
|
|
'timezone' => 'nullable|string',
|
|
'country' => 'nullable|string',
|
|
'address' => 'nullable|string',
|
|
'gps_lat' => 'nullable|numeric|between:-90,90',
|
|
'gps_long' => 'nullable|numeric|between:-180,180',
|
|
'enrollment_fee' => 'nullable|numeric|min:0',
|
|
'club_status' => 'nullable|in:active,inactive,pending',
|
|
'public_profile_enabled' => 'nullable|boolean',
|
|
'logo' => 'nullable',
|
|
'cover_image' => 'nullable',
|
|
'social_links' => 'nullable|array',
|
|
'bank_accounts' => 'nullable|array',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Validation failed',
|
|
'errors' => $validator->errors()
|
|
], 422);
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
$data = $validator->validated();
|
|
|
|
// Handle phone as JSON
|
|
if ($request->filled('phone_code') && $request->filled('phone_number')) {
|
|
$data['phone'] = [
|
|
'code' => $request->phone_code,
|
|
'number' => $request->phone_number,
|
|
];
|
|
}
|
|
|
|
// Handle logo upload
|
|
if ($request->filled('logo') && str_starts_with($request->logo, 'data:image')) {
|
|
if ($club->logo) {
|
|
Storage::disk('public')->delete($club->logo);
|
|
}
|
|
$data['logo'] = $this->handleBase64Image($request->logo, 'clubs/logos', 'logo_' . time());
|
|
}
|
|
|
|
// Handle cover image upload
|
|
if ($request->filled('cover_image') && str_starts_with($request->cover_image, 'data:image')) {
|
|
if ($club->cover_image) {
|
|
Storage::disk('public')->delete($club->cover_image);
|
|
}
|
|
$data['cover_image'] = $this->handleBase64Image($request->cover_image, 'clubs/covers', 'cover_' . time());
|
|
}
|
|
|
|
// Set status
|
|
$data['status'] = $request->input('club_status', 'active');
|
|
$data['public_profile_enabled'] = $request->boolean('public_profile_enabled', true);
|
|
|
|
// Update club
|
|
$club->update($data);
|
|
|
|
// Update social links
|
|
$club->socialLinks()->delete();
|
|
if ($request->has('social_links')) {
|
|
foreach ($request->social_links as $index => $link) {
|
|
if (!empty($link['platform']) && !empty($link['url'])) {
|
|
ClubSocialLink::create([
|
|
'tenant_id' => $club->id,
|
|
'platform' => $link['platform'],
|
|
'url' => $link['url'],
|
|
'display_order' => $index,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update bank accounts
|
|
$club->bankAccounts()->delete();
|
|
if ($request->has('bank_accounts')) {
|
|
foreach ($request->bank_accounts as $account) {
|
|
if (!empty($account['bank_name']) && !empty($account['account_name'])) {
|
|
ClubBankAccount::create([
|
|
'tenant_id' => $club->id,
|
|
'bank_name' => $account['bank_name'],
|
|
'account_name' => $account['account_name'],
|
|
'account_number' => $account['account_number'] ?? null,
|
|
'iban' => $account['iban'] ?? null,
|
|
'swift_code' => $account['swift_code'] ?? null,
|
|
'benefitpay_account' => $account['benefitpay_account'] ?? null,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Club updated successfully!',
|
|
'club' => $club
|
|
]);
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Failed to update club: ' . $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle base64 image upload.
|
|
*/
|
|
private function handleBase64Image($base64String, $folder, $filename)
|
|
{
|
|
$imageParts = explode(";base64,", $base64String);
|
|
$imageTypeAux = explode("image/", $imageParts[0]);
|
|
$extension = $imageTypeAux[1];
|
|
$imageBinary = base64_decode($imageParts[1]);
|
|
|
|
$fullPath = $folder . '/' . $filename . '.' . $extension;
|
|
Storage::disk('public')->put($fullPath, $imageBinary);
|
|
|
|
return $fullPath;
|
|
}
|
|
}
|