Adds locations table for additional location meta data; updates seeder to add locations; separates modal out into parts
This commit is contained in:
		
							parent
							
								
									c58a498e44
								
							
						
					
					
						commit
						9f3ceabd7d
					
				@ -0,0 +1,35 @@
 | 
			
		||||
<?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('locations', function (Blueprint $table) {
 | 
			
		||||
            $table->id();                                         // BIGINT PK
 | 
			
		||||
            $table->string('display_name');                       // “Home”, “Reading Terminal Market”
 | 
			
		||||
            $table->text('raw_address')->nullable();              // what the user originally typed
 | 
			
		||||
            $table->string('street')->nullable();
 | 
			
		||||
            $table->string('city')->nullable();
 | 
			
		||||
            $table->string('state', 64)->nullable();
 | 
			
		||||
            $table->string('postal', 32)->nullable();
 | 
			
		||||
            $table->string('country', 64)->nullable();
 | 
			
		||||
            $table->decimal('lat', 9, 6)->nullable();             // ±90.000000
 | 
			
		||||
            $table->decimal('lon', 9, 6)->nullable();             // ±180.000000
 | 
			
		||||
            $table->string('phone', 32)->nullable();
 | 
			
		||||
            $table->json('hours_json')->nullable();               // flexible opening-hours blob
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
 | 
			
		||||
            // optional composite for fast “near me” queries
 | 
			
		||||
            $table->index(['lat', 'lon'], 'idx_locations_lat_lon');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function down(): void
 | 
			
		||||
    {
 | 
			
		||||
        Schema::dropIfExists('locations');
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@ -9,23 +9,37 @@ return new class extends Migration
 | 
			
		||||
    public function up(): void
 | 
			
		||||
    {
 | 
			
		||||
        Schema::create('event_meta', function (Blueprint $table) {
 | 
			
		||||
 | 
			
		||||
            // FK = PK → calendarobjects.id
 | 
			
		||||
            $table->unsignedInteger('event_id')->primary();
 | 
			
		||||
 | 
			
		||||
            /* cached fields from ical blob for quick ui */
 | 
			
		||||
            // cached fields from the VEVENT
 | 
			
		||||
            $table->string('title')->nullable();
 | 
			
		||||
            $table->text('description')->nullable();
 | 
			
		||||
 | 
			
		||||
            // free-text fallback if no geocoded location
 | 
			
		||||
            $table->string('location')->nullable();
 | 
			
		||||
 | 
			
		||||
            // foreign-key to the richer locations table
 | 
			
		||||
            $table->unsignedBigInteger('location_id')->nullable();
 | 
			
		||||
            $table->foreign('location_id')
 | 
			
		||||
                  ->references('id')
 | 
			
		||||
                  ->on('locations')
 | 
			
		||||
                  ->nullOnDelete();
 | 
			
		||||
 | 
			
		||||
            // all-day flag
 | 
			
		||||
            $table->boolean('all_day')->default(false);
 | 
			
		||||
 | 
			
		||||
            /* extra metadata */
 | 
			
		||||
            // extra metadata
 | 
			
		||||
            $table->string('category')->nullable();
 | 
			
		||||
            $table->string('reminder_minutes')->nullable();
 | 
			
		||||
            $table->boolean('is_private')->default(false);
 | 
			
		||||
            $table->dateTime('start_at')->nullable();
 | 
			
		||||
            $table->dateTime('end_at')->nullable();
 | 
			
		||||
            $table->json('extra')->nullable();
 | 
			
		||||
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
 | 
			
		||||
            // FK to Sabre calendarobjects table
 | 
			
		||||
            $table->foreign('event_id')
 | 
			
		||||
                  ->references('id')
 | 
			
		||||
                  ->on('calendarobjects')
 | 
			
		||||
@ -71,10 +71,67 @@ class DatabaseSeeder extends Seeder
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *
 | 
			
		||||
         * create helper function for events to be added
 | 
			
		||||
         * create the locations connected to each event
 | 
			
		||||
         **/
 | 
			
		||||
 | 
			
		||||
        $insertEvent = function (Carbon $start, string $summary) use ($calId) {
 | 
			
		||||
        // locations
 | 
			
		||||
        $locationSeeds = [
 | 
			
		||||
            'Home'  => [       // free-text, no geo
 | 
			
		||||
                'display' => 'Home',
 | 
			
		||||
                'raw'     => null,
 | 
			
		||||
            ],
 | 
			
		||||
            'Living Room' => [
 | 
			
		||||
                'display' => 'Living Room',
 | 
			
		||||
                'raw'     => null,
 | 
			
		||||
            ],
 | 
			
		||||
            'McCahill Park' => [
 | 
			
		||||
                'display' => 'McCahill Park',
 | 
			
		||||
                'raw'     => '625 Hemlock Hollow Rd, Pittsburgh, PA 15238',
 | 
			
		||||
            ],
 | 
			
		||||
            'Meadow Park' => [
 | 
			
		||||
                'display' => 'Meadow Park',
 | 
			
		||||
                'raw'     => '2 Meadow Park Lane, Pittsburgh, PA 15215',
 | 
			
		||||
            ],
 | 
			
		||||
            'AHN Pediatrics' => [
 | 
			
		||||
                'display' => 'AHN Pediatrics',
 | 
			
		||||
                'raw'     => '3394 Saxonburg Blvd Suite 600, Glenshaw, PA 15116',
 | 
			
		||||
            ],
 | 
			
		||||
            'The Discovery School' => [
 | 
			
		||||
                'display' => 'The Discovery School',
 | 
			
		||||
                'raw'     => '4225 Middle Rd, Allison Park, PA 15101',
 | 
			
		||||
            ],
 | 
			
		||||
            'Fairview Elementary School' => [
 | 
			
		||||
                'display' => 'Fairview Elementary School',
 | 
			
		||||
                'raw'     => '738 Dorseyville Rd, Pittsburgh, PA 15238',
 | 
			
		||||
            ],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        // create the locations first
 | 
			
		||||
        $locationIdMap = [];
 | 
			
		||||
        foreach ($locationSeeds as $key => $data) {
 | 
			
		||||
            $locId = DB::table('locations')->updateOrInsert(
 | 
			
		||||
                ['display_name' => $data['display']],           // uniqueness key
 | 
			
		||||
                [
 | 
			
		||||
                    'raw_address' => $data['raw'],
 | 
			
		||||
                    'created_at'  => now(),
 | 
			
		||||
                    'updated_at'  => now(),
 | 
			
		||||
                ]
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // updateOrInsert returns boolean; fetch id explicitly
 | 
			
		||||
            $locId = DB::table('locations')->where('display_name', $data['display'])->value('id');
 | 
			
		||||
            $locationIdMap[$key] = $locId;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *
 | 
			
		||||
         * cevent creation helper function
 | 
			
		||||
         **/
 | 
			
		||||
 | 
			
		||||
        $insertEvent = function (Carbon $start,
 | 
			
		||||
                                 string $summary,
 | 
			
		||||
                                 string $locationKey) use ($calId, $locationIdMap)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            // set base vars
 | 
			
		||||
            $uid  = Str::uuid().'@kithkin.lan';
 | 
			
		||||
@ -85,6 +142,10 @@ class DatabaseSeeder extends Seeder
 | 
			
		||||
            $dtstart = $start->copy()->utc()->format('Ymd\\THis\\Z');
 | 
			
		||||
            $dtend = $end->copy()->utc()->format('Ymd\\THis\\Z');
 | 
			
		||||
 | 
			
		||||
            $locationDisplay = $locationKey;
 | 
			
		||||
            $locationRaw = $locationSeeds[$locationKey]['raw'] ?? null;
 | 
			
		||||
            $icalLocation = $locationRaw ?? $locationDisplay;
 | 
			
		||||
 | 
			
		||||
            $ical = <<<ICS
 | 
			
		||||
BEGIN:VCALENDAR
 | 
			
		||||
VERSION:2.0
 | 
			
		||||
@ -117,7 +178,8 @@ ICS;
 | 
			
		||||
                [
 | 
			
		||||
                    'title'       => $summary,
 | 
			
		||||
                    'description' => 'Automatically seeded event',
 | 
			
		||||
                    'location'    => 'Home Office',
 | 
			
		||||
                    'location'    => $locationRaw ? null : $locationDisplay,
 | 
			
		||||
                    'location_id' => $locationIdMap[$locationKey] ?? null,
 | 
			
		||||
                    'all_day'     => false,
 | 
			
		||||
                    'category'    => 'Demo',
 | 
			
		||||
                    'start_at'    => $start->copy()->utc(),
 | 
			
		||||
@ -136,23 +198,23 @@ ICS;
 | 
			
		||||
        $now = Carbon::now()->setSeconds(0);
 | 
			
		||||
 | 
			
		||||
        // 3 events today
 | 
			
		||||
        $insertEvent($now->copy(), 'Playground with James');
 | 
			
		||||
        $insertEvent($now->copy()->addHours(2), 'Lunch with Daniel');
 | 
			
		||||
        $insertEvent($now->copy()->addHours(4), 'Baseball practice');
 | 
			
		||||
        $insertEvent($now->copy(), 'Playground with James', 'McCaHill Park');
 | 
			
		||||
        $insertEvent($now->copy()->addHours(2), 'Lunch with Daniel', 'Home');
 | 
			
		||||
        $insertEvent($now->copy()->addHours(4), 'Baseball practice', 'Meadow Park');
 | 
			
		||||
 | 
			
		||||
        // 1 event 3 days ago
 | 
			
		||||
        $past = $now->copy()->subDays(3)->setTime(10, 0);
 | 
			
		||||
        $insertEvent($past, 'Kids doctors appointments');
 | 
			
		||||
        $insertEvent($past, 'Kids doctors appointments', 'AHN Pediatrics');
 | 
			
		||||
 | 
			
		||||
        // 1 event 2 days ahead
 | 
			
		||||
        $future2 = $now->copy()->addDays(2)->setTime(14, 0);
 | 
			
		||||
        $insertEvent($future2, 'Teacher conference (Nuthatches)');
 | 
			
		||||
        $insertEvent($future2, 'Teacher conference (Nuthatches)', 'The Discovery School');
 | 
			
		||||
 | 
			
		||||
        // 2 events 5 days ahead
 | 
			
		||||
        $future5a = $now->copy()->addDays(5)->setTime(9, 0);
 | 
			
		||||
        $future5b = $future5a->copy()->addHours(2);
 | 
			
		||||
        $insertEvent($future5a, 'Teacher conference (3rd grade)');
 | 
			
		||||
        $insertEvent($future5b, 'Family game night');
 | 
			
		||||
        $insertEvent($future5a, 'Teacher conference (3rd grade)', 'Fairview Elementary');
 | 
			
		||||
        $insertEvent($future5b, 'Family game night', 'Living Room');
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         *
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								resources/font/bogart-bold.ttf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								resources/font/bogart-bold.ttf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										3
									
								
								resources/views/components/modal/body.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								resources/views/components/modal/body.blade.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
<section class="flex flex-col px-8 pb-6">
 | 
			
		||||
    {{ $slot }}
 | 
			
		||||
</section>
 | 
			
		||||
							
								
								
									
										9
									
								
								resources/views/components/modal/title.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								resources/views/components/modal/title.blade.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
@props([
 | 
			
		||||
    'border' => false,
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
<header @class(['px-8 py-6', 'header--with-border' => $border])>
 | 
			
		||||
    <h2 class="text-lg font-semibold">
 | 
			
		||||
        {{ $slot }}
 | 
			
		||||
    </h2>
 | 
			
		||||
</header>
 | 
			
		||||
@ -1,10 +1,9 @@
 | 
			
		||||
<x-modal.content>
 | 
			
		||||
    <div class="p-6 space-y-4">
 | 
			
		||||
        <h2 class="text-lg font-semibold">
 | 
			
		||||
            {{ $event->meta->title ?? '(no title)' }}
 | 
			
		||||
        </h2>
 | 
			
		||||
 | 
			
		||||
        <p class="text-sm text-gray-600">
 | 
			
		||||
    <x-modal.title>
 | 
			
		||||
        {{ $event->meta->title ?? '(no title)' }}
 | 
			
		||||
    </x-modal.title>
 | 
			
		||||
    <x-modal.body>
 | 
			
		||||
        <p class="text-gray-700">
 | 
			
		||||
            {{ $start->format('l, F j, Y · g:i A') }}
 | 
			
		||||
            @unless ($start->equalTo($end))
 | 
			
		||||
                 – 
 | 
			
		||||
@ -15,13 +14,13 @@
 | 
			
		||||
        </p>
 | 
			
		||||
 | 
			
		||||
        @if ($event->meta->location)
 | 
			
		||||
            <p class="text-sm"><strong>Where:</strong> {{ $event->meta->location }}</p>
 | 
			
		||||
        <p><strong>Where:</strong> {{ $event->meta->location }}</p>
 | 
			
		||||
        @endif
 | 
			
		||||
 | 
			
		||||
        @if ($event->meta->description)
 | 
			
		||||
            <div class="prose max-w-none text-sm">
 | 
			
		||||
                {!! nl2br(e($event->meta->description)) !!}
 | 
			
		||||
            </div>
 | 
			
		||||
        <div>
 | 
			
		||||
            {!! nl2br(e($event->meta->description)) !!}
 | 
			
		||||
        </div>
 | 
			
		||||
        @endif
 | 
			
		||||
    </div>
 | 
			
		||||
    </x-modal.body>
 | 
			
		||||
</x-modal.content>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user