TheftController

Bike Thief Hunt 🦾👮 -> 🚴‍♀️🦹‍♀️
<p>Bike Thief Hunt 🦾👮 -> 🚴‍♀️🦹‍♀️</p>

<p>Step 0 of 5</p>
<h2>0. Start a Bike Thief Hunt</h2>

<p>Step 1 of 5</p>
<h2>1. Take Photos of the Crime Scene</h2>


<p>Step 2 of 5</p>
<h2>2. Find My Stolen Bike</h2>

<p>Step 3 of 5</p>
<h2>3. Ring politiet</h2>

<p>Step 3 of 5</p>
<h2>3. tell Whee!</h2>
<p>Add investi-Gator 🐊 on Airtag</p>

<p>Step 4 of 5</p>
<h2>4. Police Report</h2>

<p>Step 5 of 5</p>
<h2>Sykkelen er Gjenfunnet 🥳</h2>
<h2>🚴‍♀️ er Gjenfunnet 🥳</h2>

<p>Step 5 of 5</p>
<h2>Loot</h2>

<p>Step 5 of 5</p>
<h2>Thanks!</h2>

Bike Thief Hunt 🦾👮 -> 🚴‍♀️🦹‍♀️
<p>Bike Thief Hunt 🦾👮 -> 🚴‍♀️🦹‍♀️</p>

<p>Step 0 of 5</p>
<h2>0. Start a Bike Thief Hunt</h2>

<p>Step 1 of 5</p>
<h2>1. Take Photos of the Crime Scene</h2>


<p>Step 2 of 5</p>
<h2>2. Find My Stolen Bike</h2>

<p>Step 3 of 5</p>
<h2>3. Ring politiet</h2>

<p>Step 3 of 5</p>
<h2>3. tell Whee!</h2>
<p>Add investi-Gator 🐊 on Airtag</p>

<p>Step 4 of 5</p>
<h2>4. Police Report</h2>

<p>Step 5 of 5</p>
<h2>Sykkelen er Gjenfunnet 🥳</h2>
<h2>🚴‍♀️ er Gjenfunnet 🥳</h2>

<p>Step 5 of 5</p>
<h2>Loot</h2>

<p>Step 5 of 5</p>
<h2>Thanks!</h2>

// New in Migration
            $table->string('police_is_hunting')->nullable();
            $table->string('police_say_no')->nullable();

TODO: find all “nouns”

It’s not nouns inside the Theft migration

Using PHP Enums for (what…?) Types

Instead of database enums, we use PHP enums for flexibility.

Example enum:


enum TalkType: string
{
    case Lightning = 'lightning';
    case Standard = 'standard';
    case Keynote = 'keynote';
}

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        // Server side validation
        // request()->validate([
        //     'what_happened' => 'nullable',
        // ]);

        // Create a row in our database
        $theft = Theft::create([
            'photos_taken' => request('photos_taken'),
        ]);

        return redirect('/thefts/{id}/edit');
    }
<!-- Template form at  -->
<div>
    @csrf
    <div>
        <!-- need a variable in title -->

        <div>
            <div>
                <div>
                    <input 
                        type="radio" 
                        id="photos_taken" 
                        name="photos_taken" 
                        value="no" 
                    />
                    <label for="photos_taken">Jeg tok bilder</label>
                </div>        
                    @error("photos_taken")
                        <p>{{ $message }}</p>
                    @enderror
                </div>
            </div>
        </div>
    </div>
    <div>
        <a href="/thefts/{{ $theft->id }}">Cancel</a>
        <!-- need a variable in button -->
        <button type="submit">Ok,  videre</button>
    </div>
</div>
            

return new class extends Migration
{
    /**
     * Run the migrations.
     *      Customer_id = kkjjjh ?
     * photos_taken
     */
    public function up(): void
    {
        Schema::create('thefts', function (Blueprint $table) {
            $table->id();
            $table->boolean('photos_taken')->default(true);
            $table->boolean('find_my_activated')->default(false);
            $table->text('find_my_not_working')->nullable();
            $table->boolean('called_police')->nullable();
            $table->boolean('bike_found')->nullable();
            $table->boolean('whee_report')->nullable();
            $table->boolean('police_report')->nullable();
            $table->boolean('terminate_whee')->nullable();
            $table->boolean('new_bike')->nullable();
            // $table->string('archive_report')->default('false');
            $table->timestamps();
        });
    }

<p>Min Side</p>
<p>Trinn 2 av 3</p>
<h2>2. Sjekk hvor sykkelen er</h2>


<a
    href="#"
    class="text-black-40 hover:text-red-40 text-sm font-medium transition-colors"
>
    Åpne: Hvor er/find my -> objekter.
</a>

<p>Velg Whee! - ditt navn</p>
<a
    href="/thefts/create"
    class="text-black-40 hover:text-red-40 text-sm font-medium transition-colors"
>
    Tilbake
</a>

<br />
<a
    href="/thefts/3-callcops"
    class="text-black-40 hover:text-red-40 text-sm font-medium transition-colors"
>
    Ok,  videre
</a>
<br />
<a
    href="/thefts/#"
    class="text-black-40 hover:text-red-40 text-sm font-medium transition-colors"
>
    Det, går ikke
</a>
Route::get('/bet', function (S $s) {
    $returnUrl = route('user.payments.index');
    $port = $s->createBillPortaSess(
        $u->s_cu_d,
        $returnUrl
    );

    return redirect($port);
})


    $returnUrl = route('user.payments.index');
    $portalUrl = $stripeService->createBillingPortalSession(
        $user->stripe_customer_id,
        $returnUrl
    );

    return redirect($portalUrl);

    // x
Route::get('/bet', function (StripeService $stripeService) {
    $returnUrl = route('user.payments.index');

    $portalUrl = $stripeService->createBillingPortalSession(
        $user->stripe_customer_id,
        $returnUrl
    );

    return redirect($portalUrl);
})
// db / migrations / create_thefts_table  ✅

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('thefts', function (Blueprint $table) {
            $table->id();
            $table->text('what_happened')->nullable();
            $table->text('where_happened')->nullable();
            $table->string('file_paths')->nullable();
            // $table->string('archive_report')->default('false');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('thefts');
    }
};

<?php
// App\Models/ Theft ✅
namespace App\Models; 

use Illuminate\Database\Eloquent\Model; 

class Theft extends Model 
{
    // deleted this for now: , 'archive_report' 
    protected $fillable = ['what_happened', 'where_happened', 'file_paths'];


    protected $casts = [
        'file_paths' => 'array', // Laravel will JSON encode/decode automatically
    ];
}


// routes/web.php
<?php

use App\Http\Controllers\TheftController;
use Illuminate\Support\Facades\Route;

// Set Norwegian verbs for resource routes
Route::resourceVerbs([
    'create' => 'opprett',
    'edit' => 'rediger',
]);

//  ✅
// Read a list of our user's Theft reports, by what_happened 
Route::get('/thefts', [TheftController::class, 'index']);

// Create View a Theft Form and create a theft report, in ep (16)
Route::get('/thefts/create', [TheftController::class, 'create']);

// Store a Theft report in the database
Route::post('/theft', [TheftController::class, 'store']);

// Show our user's Theft report
Route::get('/thefts/{id}', [TheftController::class, 'show']);

// Edit form for our user's Theft report
Route::get('/thefts/{id}/edit', [TheftController::class, 'edit']);

// Update our user's Theft report in the database
Route::patch('/thefts/{id}', [TheftController::class, 'update']);

// Destroy our user's Theft report in the database
Route::delete('/thefts/{id}', [TheftController::class, 'destroy']);

// TheftController

<?php

namespace App\Http\Controllers;

use App\Models\Theft;
use Illuminate\Http\Request;

class TheftController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        return view('thefts.index', [
            'thefts' => Theft::all()
        ]);
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        return view('thefts.create', ['theft' => new Theft]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {

        // Server side validation 
        // 'image_upload' => 'file|image|max:2000',
        request()->validate([
            'what_happened' => 'required',
            'where_happened' => 'nullable',
            'image_upload' => 'max:2000',
            
        ]); 
            
        $image_array = [];
        if ($request->hasFile('image_upload')) {
            foreach ($request->file('image_upload') as $file) {

                // Store the file in the Pub / images directory
                $filePath = $file->store('images', 'public');
                // Add file Path to our array
                $image_array[] = $filePath;
            }
        }
        // Create a row in our database
        $theft = Theft::create([
            'what_happened' => request('what_happened'),
            'where_happened' => request('where_happened'),
            'file_paths' => $image_array,
            // $request->file('image_upload')->store('images', 'public'),
        ]);
        
        return redirect('/thefts/'. $theft->id);      

    }

    /**
     * Display the specified resource.
     */
    public function show(Theft $theft, $id)
    {
        $theft = Theft::findOrFail($id);
        $files = $theft->file_paths;
        
        if ($theft) {        
            return view('thefts.show', ['theft' => $theft, 'files' => $files]);
        }

        return redirect('/thefts');
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Theft $theft, $id)
    {
        $theft = Theft::find($id);
    
        if ($theft) {        
            return view('thefts.edit', ['theft' => $theft]);
        }

        return redirect('/thefts');
        }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Theft $theft, $id)
    {
        // Server side validation 
        // 'image_upload' => 'file|image|max:2000', 
        $validated = $request->validate([
            'what_happened' => '',
            'where_happened' => '',
            'image_upload' => '',
        ]); 
        
        
        $image_array = [];
        if ($request->hasFile('image_upload')) {
            foreach ($request->file('image_upload') as $file) {

                // Store the file in the Pub / images directory
                $filePath = $file->store('images', 'public');
                // Add file Path to our array
                $image_array[] = $filePath; // pluss one here
            }
        }

        // authenticate (on hold)
        
        $theft = Theft::findOrFail($id);
    
        $theft->what_happened = request('what_happened');
        $theft->where_happened = request('where_happened');
        // $theft->archive_report = request('archive_report');
        $theft->file_paths = $image_array;
        $theft->save($validated);
    
        return redirect('/thefts/'. $theft->id);        
    }

    /**
     * Wait with: Remove the specified resource from storage.
     */
    public function destroy(Theft $theft, $id)
    {
        $gateway = Theft::find($id);
        // Research dirty delete
        
        if ($gateway) {        
            return view('thefts.show', ['gateway' => $gateway]);
        }
    
        return redirect('/thefts');
        
    }
}


// create.blade.php
    <!-- Theft form at http://whee-laravel.test/thefts/create  -->
    <form method="POST" action="/theft" enctype="multipart/form-data">
        <h2>Start sykkeltyv respons  🦾👮 -> 🚴‍♀️</h2>
        @include('thefts.template')
    </form>

// edit.blade.php

    <!-- Theft form at http://whee-laravel.test/thefts/{id}/edit  -->
<form method="POST" action="/thefts/{{ $theft->id }}" enctype="multipart/form-data">
    <h2>Oppdater sykkeltyv respons  🦾👮 -> 🚴‍♀️</h2>
    
    @method('PATCH')
    @include('thefts.template')

</form>


// index.blade.php
 <!-- View a list of Thefts, by what_happened at /thefts -->
<div>
    <ul>
        @foreach ($thefts as $theft)
            <li class="hover:underline ">
                <a href="/thefts/{{ $theft['id'] }}">
                    {{ $theft['what_happened'] }}. 
                </a>
            </li>
        @endforeach    
    </ul>
</div>

// show.blade.php
<h2>
    <strong>Hva skjedde?</strong> 
</h2>

<p>{{ $theft['what_happened'] }} </p>

<p>{{ $theft['where_happened'] }} </p>

<div>
    
            
    
    @foreach ($files as $file)
        @if($file)    
            <img src="{{ asset($file) }}" alt="image" />
        @endif    

        
    @endforeach    
    
</div>

<p>Gi oss gjerne mer informasjon</p>

<a href="/thefts/{{ $theft->id }}/edit">Oppdater din tyverirapport</a>

// template.blade.php

<!-- Template form at  -->
    <div>
    @csrf 
        <div>
            <!-- need a variable in title -->
        
        

            <div>
                <div>
                    <label for="title">Hva skjedde?</label>
                    <div>
                        <div>
                            <input
                                placeholder="🥔 Potet på 🛴  " 
                                type="text" 
                                name="what_happened" 
                                id="what_happened"
                                value="{{ old('what_happened', $theft->what_happened ?? '' )}}" 
                            >
                        </div>
                        @error('what_happened')
                            <p>{{ $message }}</p>
                        @enderror
                    </div>
                </div>

                <div>
                    <label for="title">Hvor skjedde?</label>
                    <div>
                        <div>
                            <input
                                placeholder="🥔 Potet på 🛴  " 
                                type="text" 
                                name="where_happened" 
                                id="where_happened" 
                                value="{{ $theft->where_happened }}" 
                            >
                        </div>
                        @error('where_happened')
                            <p>{{ $message }}</p>
                        @enderror
                    </div>
                </div>

                <div>
                    <label for="image_upload">Oppdater bilde</label>
                    <div>
                        <div>
                            <!-- How to dirty-dont-delete-images-on-empty-edit ? -->
                            <input
                                type="file" 
                                name="image_upload[]" 
                                id="image_upload" 
                                accept="image/*"
                                multiple
                            >
                        </div>
                        @error('image_upload')
                            <p>{{ $message }}</p>
                        @enderror
                    
                    
                    </div>
                </div>
                <!-- <div>
                    <label for="archive_report">Archive this theft report</label>
                    <div>
                        <div>
                            <input
                                placeholder="false 🦹" 
                                type="boolean" 
                                name="archive_report" 
                                id="archive_report" 
                                value="{{ $theft->archive_report }}" 
                            >
                        </div>
                        @error('archive_report')
                            <p>{{ $message }}</p>
                        @enderror
                    </div>
                </div> -->
            
        </div>
        </div>
    <div>
        <a href="/thefts/{{ $theft->id }}">Cancel</a>
                    <!-- need a variable in button -->
        <button type="submit">Lagre</button>
    </div>
    


// public.blade.php
                <nav class="flex items-center gap-x-4">
                    <a
                        href="/thefts/create"
                        class="text-sm font-medium text-black-40 hover:text-red-40 transition-colors"
                    >
                        Sykkeltyveri 
                    </a>
                </nav>



// app \ Policies / TheftPolicy
<?php

namespace App\Policies;

use App\Models\Theft;
use App\Models\User;

class TheftPolicy
{
    /**
     * Determine whether the user can view any models.
     */
    public function viewAny(User $user): bool
    {
        // All authenticated users can view thefts (controller filters to their own)
        return true;
    }

    /**
     * Determine whether the user can view the model.
     */
    public function view(User $user, Theft $theft): bool
    {
        // Users can only view their own thefts
        return $user->id === $theft->user_id;
    }

    /**
     * Determine whether the user can create models.
     */
    public function create(User $user): bool
    {
        // All authenticated users can create thefts
        return true;
    }

    /**
     * Determine whether the user can update the model.
     */
    public function update(User $user, Theft $theft): bool
    {
        // Users can only update their own thefts
        return $user->id === $theft->user_id;
    }

    /**
     * Determine whether the user can delete the model.
     */
    public function delete(User $user, Theft $theft): bool
    {
        // Users can only delete their own thefts
        return $user->id === $theft->user_id;
    }

    /**
     * Determine whether the user can restore the model.
     */
    public function restore(User $user, Theft $theft): bool
    {
        // Users can only restore their own thefts
        return $user->id === $theft->user_id;
    }

    /**
     * Determine whether the user can permanently delete the model.
     */
    public function forceDelete(User $user, Theft $theft): bool
    {
        // Users can only permanently delete their own thefts
        return $user->id === $theft->user_id;
    }
}