Преглед изворни кода

feat: :sparkles: feat (eventos) criado eventos na landingpage e web

foi criado o cadastro de eventos no layout adm, e a exibicao dos eventos na landingpage, de forma dinamica

fase:dev | origin:escopo
Gustavo Zanatta пре 5 часа
родитељ
комит
79c7a39001

+ 13 - 0
app/Enums/EventTypeEnum.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace App\Enums;
+
+use App\Traits\EnumHelper;
+
+enum EventTypeEnum: string
+{
+    use EnumHelper;
+
+    case CULTURA = 'cultura';
+    case ESPORTE = 'esporte';
+}

+ 121 - 0
app/Http/Controllers/EventController.php

@@ -0,0 +1,121 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Http\Requests\EventCoverRequest;
+use App\Http\Requests\EventRequest;
+use App\Http\Requests\UploadMediaRequest;
+use App\Http\Resources\EventResource;
+use App\Http\Resources\MediaResource;
+use App\Services\EventService;
+use App\Services\MediaService;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+
+class EventController extends Controller
+{
+    public function __construct(
+        protected EventService $service,
+        protected MediaService $mediaService,
+    ) {}
+
+    public function index(): JsonResponse
+    {
+        $events = $this->service->getAll();
+        return $this->successResponse(payload: EventResource::collection($events));
+    }
+
+    public function show(int $id): JsonResponse
+    {
+        $event = $this->service->findById($id);
+
+        if (!$event) {
+            return $this->errorResponse(message: __('messages.not_found'));
+        }
+
+        return $this->successResponse(payload: new EventResource($event));
+    }
+
+    public function store(EventRequest $request): JsonResponse
+    {
+        $event = $this->service->create($request->validated());
+
+        return $this->successResponse(
+            payload: new EventResource($event),
+            message: __('messages.created'),
+            code: 201,
+        );
+    }
+
+    public function update(EventRequest $request, int $id): JsonResponse
+    {
+        $event = $this->service->update($id, $request->validated());
+
+        if (!$event) {
+            return $this->errorResponse(message: __('messages.not_found'));
+        }
+
+        return $this->successResponse(
+            payload: new EventResource($event),
+            message: __('messages.updated'),
+        );
+    }
+
+    public function reorder(Request $request): JsonResponse
+    {
+        $items = $request->validate([
+            '*.id'    => 'required|integer|exists:events,id',
+            '*.order' => 'required|integer|min:0',
+        ]);
+
+        $this->service->reorder($items);
+
+        return $this->successResponse(message: __('messages.updated'));
+    }
+
+    public function destroy(int $id): JsonResponse
+    {
+        $this->service->delete($id);
+        return $this->successResponse(message: __('messages.deleted'), code: 204);
+    }
+
+    public function uploadCover(EventCoverRequest $request, int $id): JsonResponse
+    {
+        $event = $this->service->uploadCover($id, $request->file('image'));
+
+        if (!$event) {
+            return $this->errorResponse(message: __('messages.not_found'));
+        }
+
+        return $this->successResponse(
+            payload: new EventResource($event),
+            message: __('messages.updated'),
+        );
+    }
+
+    public function removeCover(int $id): JsonResponse
+    {
+        $event = $this->service->removeCover($id);
+
+        if (!$event) {
+            return $this->errorResponse(message: __('messages.not_found'));
+        }
+
+        return $this->successResponse(
+            payload: new EventResource($event),
+            message: __('messages.updated'),
+        );
+    }
+
+    public function uploadMedia(UploadMediaRequest $request, int $id): JsonResponse
+    {
+        $media = $this->mediaService->upload($request->file('file'), 'event', $id, 'imagem');
+        return $this->successResponse(payload: new MediaResource($media), code: 201);
+    }
+
+    public function deleteMedia(int $id, int $mediaId): JsonResponse
+    {
+        $this->mediaService->delete($mediaId);
+        return $this->successResponse(message: __('messages.deleted'), code: 204);
+    }
+}

+ 15 - 0
app/Http/Requests/EventCoverRequest.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class EventCoverRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'image' => 'required|image|max:8192',
+        ];
+    }
+}

+ 29 - 0
app/Http/Requests/EventRequest.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Http\Requests;
+
+use App\Enums\EventTypeEnum;
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Validation\Rule;
+
+class EventRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        $rules = [
+            'title'       => 'sometimes|string|max:255',
+            'description' => 'sometimes|nullable|string',
+            'date'        => 'sometimes|nullable|date',
+            'time'        => 'sometimes|nullable|date_format:H:i',
+            'type'        => ['sometimes', Rule::enum(EventTypeEnum::class)],
+            'order'       => 'sometimes|integer|min:0',
+        ];
+
+        if ($this->isMethod('post')) {
+            $rules['title'] = 'required|string|max:255';
+            $rules['type']  = ['required', Rule::enum(EventTypeEnum::class)];
+        }
+
+        return $rules;
+    }
+}

+ 33 - 0
app/Http/Resources/EventResource.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Support\Facades\Storage;
+
+class EventResource extends JsonResource
+{
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'          => $this->id,
+            'title'       => $this->title,
+            'description' => $this->description,
+            'date'        => $this->date?->format('Y-m-d'),
+            'time'        => $this->time
+                                 ? Carbon::parse($this->time)->format('H:i')
+                                 : null,
+            'type'        => $this->type,
+            'cover_path'  => $this->cover_path,
+            'cover_url'   => $this->cover_path
+                                 ? Storage::disk('s3')->temporaryUrl($this->cover_path, now()->addHours(24))
+                                 : null,
+            'order'       => $this->order,
+            'media'       => $this->whenLoaded('media', fn() => MediaResource::collection($this->media)),
+            'created_at'  => Carbon::parse($this->created_at)->format('Y-m-d H:i:s'),
+            'updated_at'  => Carbon::parse($this->updated_at)->format('Y-m-d H:i:s'),
+        ];
+    }
+}

+ 28 - 0
app/Models/Event.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Models;
+
+use App\Enums\EventTypeEnum;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Database\Eloquent\SoftDeletes;
+
+class Event extends Model
+{
+    use SoftDeletes;
+
+    protected $guarded = ['id'];
+
+    protected function casts(): array
+    {
+        return [
+            'date' => 'date',
+            'type' => EventTypeEnum::class,
+        ];
+    }
+
+    public function media(): HasMany
+    {
+        return $this->hasMany(Media::class, 'source_id')->where('source', 'event');
+    }
+}

+ 104 - 0
app/Services/EventService.php

@@ -0,0 +1,104 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\Event;
+use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Http\UploadedFile;
+use Illuminate\Support\Facades\Storage;
+
+class EventService
+{
+    public function __construct(protected MediaService $mediaService) {}
+
+    public function getAll(): Collection
+    {
+        return Event::with('media')->orderBy('order')->orderBy('id')->get();
+    }
+
+    public function findById(int $id): ?Event
+    {
+        return Event::with('media')->find($id);
+    }
+
+    public function create(array $data): Event
+    {
+        if (!isset($data['order'])) {
+            $data['order'] = Event::max('order') + 1;
+        }
+
+        $event = Event::create($data);
+        return $event->load('media');
+    }
+
+    public function update(int $id, array $data): ?Event
+    {
+        $model = Event::find($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh('media');
+    }
+
+    public function reorder(array $items): void
+    {
+        foreach ($items as $item) {
+            Event::where('id', $item['id'])->update(['order' => $item['order']]);
+        }
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = Event::find($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        if ($model->cover_path) {
+            Storage::disk('s3')->delete($model->cover_path);
+        }
+
+        $model->media->each(fn($media) => $this->mediaService->delete($media->id));
+
+        return $model->delete();
+    }
+
+    public function uploadCover(int $id, UploadedFile $file): ?Event
+    {
+        $model = Event::find($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        if ($model->cover_path) {
+            Storage::disk('s3')->delete($model->cover_path);
+        }
+
+        $model->cover_path = $file->store("events/{$id}/cover", 's3');
+        $model->save();
+
+        return $model->fresh('media');
+    }
+
+    public function removeCover(int $id): ?Event
+    {
+        $model = Event::find($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        if ($model->cover_path) {
+            Storage::disk('s3')->delete($model->cover_path);
+            $model->cover_path = null;
+            $model->save();
+        }
+
+        return $model->fresh('media');
+    }
+}

+ 32 - 0
database/migrations/2026_08_10_000005_create_events_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        Schema::create('events', function (Blueprint $table) {
+            $table->id();
+            $table->string('title');
+            $table->text('description')->nullable();
+            $table->date('date')->nullable();
+            $table->time('time')->nullable();
+            $table->string('type')->default('cultura');
+            $table->string('cover_path')->nullable();
+            $table->unsignedSmallInteger('order')->default(0);
+            $table->timestamps();
+            $table->softDeletes();
+
+            $table->index('order');
+            $table->index('type');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('events');
+    }
+};

+ 33 - 0
routes/authRoutes/event.php

@@ -0,0 +1,33 @@
+<?php
+
+use App\Http\Controllers\EventController;
+use Illuminate\Support\Facades\Route;
+
+Route::controller(EventController::class)->prefix('company-events')->group(function () {
+    Route::post('/', 'store')
+        ->middleware('permission:configuracoes-empresa,add');
+
+    Route::put('/reorder', 'reorder')
+        ->middleware('permission:configuracoes-empresa,edit');
+
+    Route::get('/{id}', 'show')
+        ->middleware('permission:configuracoes-empresa,view');
+
+    Route::put('/{id}', 'update')
+        ->middleware('permission:configuracoes-empresa,edit');
+
+    Route::delete('/{id}', 'destroy')
+        ->middleware('permission:configuracoes-empresa,delete');
+
+    Route::post('/{id}/cover', 'uploadCover')
+        ->middleware('permission:configuracoes-empresa,edit');
+
+    Route::delete('/{id}/cover', 'removeCover')
+        ->middleware('permission:configuracoes-empresa,edit');
+
+    Route::post('/{id}/media', 'uploadMedia')
+        ->middleware('permission:configuracoes-empresa,edit');
+
+    Route::delete('/{id}/media/{mediaId}', 'deleteMedia')
+        ->middleware('permission:configuracoes-empresa,edit');
+});

+ 8 - 0
routes/noAuthRoutes/event.php

@@ -0,0 +1,8 @@
+<?php
+
+use App\Http\Controllers\EventController;
+use Illuminate\Support\Facades\Route;
+
+Route::controller(EventController::class)->group(function () {
+    Route::get('/company-events', 'index');
+});