diff --git a/app/Http/Controllers/ProductCRUDController.php b/app/Http/Controllers/ProductCRUDController.php index 10aa74e4..23264ca2 100644 --- a/app/Http/Controllers/ProductCRUDController.php +++ b/app/Http/Controllers/ProductCRUDController.php @@ -16,6 +16,7 @@ class ProductCRUDController extends CRUDController 'price' => 'required|integer', 'stock' => 'required|integer', 'edition_id' => 'required|exists:editions,id', + 'image' => 'nullable|mimes:jpg,jpeg,png|max:1024', ]; protected array $search = ['name', 'price', 'stock']; @@ -26,4 +27,35 @@ protected function with(): array 'editions' => Edition::all(), ]; } + + protected function created(array $new): ?array + { + $product = Product::create([ + 'name' => $new['name'], + 'price' => $new['price'], + 'stock' => $new['stock'], + 'edition_id' => $new['edition_id'], + ]); + + if (isset($new['image'])) { + $product->updateImageProduct($new['image']); + } + + return null; + } + + protected function updated($old, array $new): ?array + { + + if (isset($new['image'])) { + $old->updateImageProduct($new['image']); + } + + return [ + 'name' => $new['name'], + 'price' => $new['price'], + 'stock' => $new['stock'], + 'edition_id' => $new['edition_id'], + ]; + } } diff --git a/app/Http/Controllers/ShopController.php b/app/Http/Controllers/ShopController.php new file mode 100644 index 00000000..7487ab8c --- /dev/null +++ b/app/Http/Controllers/ShopController.php @@ -0,0 +1,22 @@ +input('edition'); + + if ($edition === null) { + return response('No edition found', 500); + } + + return Inertia::render('Shop', [ + 'products' => $edition->products, + ]); + } +} diff --git a/app/Models/Product.php b/app/Models/Product.php index 1ac43bb9..be1d1224 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Traits\HasImageProduct; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -10,6 +11,7 @@ class Product extends Model { use HasFactory; + use HasImageProduct; /** * The attributes that are mass assignable. @@ -21,6 +23,11 @@ class Product extends Model 'price', 'stock', 'edition_id', + 'image_path', + ]; + + protected $appends = [ + 'image_product_url', ]; public function edition(): BelongsTo diff --git a/app/Traits/HasCV.php b/app/Traits/HasCV.php index 8ec7fb1b..7aab4bbc 100644 --- a/app/Traits/HasCV.php +++ b/app/Traits/HasCV.php @@ -38,7 +38,7 @@ public function updateCV(UploadedFile $cv, $storagePath = 'cvs') */ public function deleteCV() { - //missing check to verify if user can manage CVs + //#TODO: missing check to verify if user can manage CVs if (is_null($this->cv_path)) { return; diff --git a/app/Traits/HasImageProduct.php b/app/Traits/HasImageProduct.php new file mode 100644 index 00000000..991d4335 --- /dev/null +++ b/app/Traits/HasImageProduct.php @@ -0,0 +1,70 @@ +image_path, function ($previous) use ($image, $storagePath) { + if ($previous) { + Storage::disk($this->ImageProductDisk())->delete($previous); + } + + $this->forceFill([ + 'image_path' => $image->storePublicly( + $storagePath, ['disk' => $this->ImageProductDisk()] + ), + ])->save(); + }); + } + + /** + * Delete the user's CV. + * + * @return void + */ + public function deleteImageProduct() + { + if (is_null($this->image_path)) { + return; + } + + Storage::disk($this->ImageProductDisk())->delete($this->image_path); + + $this->forceFill([ + 'image_path' => null, + ])->save(); + } + + /** + * Get the URL to the user's CV. + */ + public function ImageProductUrl(): Attribute + { + return Attribute::get(function () { + return Storage::disk($this->ImageProductDisk())->url($this->image_path); + }); + } + + /** + * Get the disk that CVs should be stored on. + * + * @return string + */ + protected function ImageProductDisk() + { + return config('jetstream.product_image_disk', 'public'); + } +} diff --git a/config/jetstream.php b/config/jetstream.php index ac6099f6..3a1d273d 100644 --- a/config/jetstream.php +++ b/config/jetstream.php @@ -78,5 +78,6 @@ 'profile_photo_disk' => 'public', 'cv_disk' => 'public', + 'product_image_disk' => 'public', ]; diff --git a/database/migrations/2023_09_27_131517_add_product_image.php b/database/migrations/2023_09_27_131517_add_product_image.php new file mode 100644 index 00000000..8f788c50 --- /dev/null +++ b/database/migrations/2023_09_27_131517_add_product_image.php @@ -0,0 +1,28 @@ +string('image_path', 2048)->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('products', function (Blueprint $table) { + $table->dropColumn('image_path'); + }); + } +}; diff --git a/resources/js/Components/HamburgerMenu.vue b/resources/js/Components/HamburgerMenu.vue index ceabd10a..17477ed6 100644 --- a/resources/js/Components/HamburgerMenu.vue +++ b/resources/js/Components/HamburgerMenu.vue @@ -5,6 +5,7 @@ import route, { type QueryParams, type RouteParamsWithQueryOverload, } from "ziggy-js"; +import type Competition from "@/Types/Competition"; interface Route { label: string; @@ -17,7 +18,7 @@ const open = ref(false); const props = defineProps<{ options: { pages: Routes; - activities: Routes; + competitions: Competition[]; editions: number[]; }; }>(); @@ -78,21 +79,16 @@ watch(open, () => {

- Atividades + Competições

diff --git a/resources/js/Components/Navbar.vue b/resources/js/Components/Navbar.vue index c09ae544..a8e897d3 100644 --- a/resources/js/Components/Navbar.vue +++ b/resources/js/Components/Navbar.vue @@ -36,6 +36,7 @@ const pageRoutes: Routes = { day: 1, }, }, + shop: { label: "Loja" }, team: { label: "Equipa" }, // sponsors: { label: "Patrocínios" }, // contacts: { label: "Contactos" }, @@ -53,7 +54,7 @@ const editionRoutes = [2022, 2021, 2020, 2019, 2018]; const options = { pages: pageRoutes, - activities: activityRoutes, + competitions: usePage().props.competitions, editions: editionRoutes, }; diff --git a/resources/js/Components/Shop/ShopItem.vue b/resources/js/Components/Shop/ShopItem.vue new file mode 100644 index 00000000..799d1b3b --- /dev/null +++ b/resources/js/Components/Shop/ShopItem.vue @@ -0,0 +1,51 @@ + + + diff --git a/resources/js/Pages/CRUD/Product/Create.vue b/resources/js/Pages/CRUD/Product/Create.vue index 018bfb6f..448552af 100644 --- a/resources/js/Pages/CRUD/Product/Create.vue +++ b/resources/js/Pages/CRUD/Product/Create.vue @@ -1,4 +1,5 @@