diff --git a/database/migrations/2025_07_29_000000_create_locations_table.php b/database/migrations/2025_07_29_000000_create_locations_table.php new file mode 100644 index 0000000..eee86cb --- /dev/null +++ b/database/migrations/2025_07_29_000000_create_locations_table.php @@ -0,0 +1,35 @@ +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'); + } +}; diff --git a/database/migrations/2025_07_15_000002_create_event_meta_table.php b/database/migrations/2025_07_29_000001_create_event_meta_table.php similarity index 68% rename from database/migrations/2025_07_15_000002_create_event_meta_table.php rename to database/migrations/2025_07_29_000001_create_event_meta_table.php index ba7f524..04bef30 100644 --- a/database/migrations/2025_07_15_000002_create_event_meta_table.php +++ b/database/migrations/2025_07_29_000001_create_event_meta_table.php @@ -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') diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 5647a8b..c597d89 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -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 = << $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'); /** * diff --git a/resources/font/bogart-bold.ttf b/resources/font/bogart-bold.ttf new file mode 100644 index 0000000..555baa4 Binary files /dev/null and b/resources/font/bogart-bold.ttf differ diff --git a/resources/views/components/modal/body.blade.php b/resources/views/components/modal/body.blade.php new file mode 100644 index 0000000..11b28be --- /dev/null +++ b/resources/views/components/modal/body.blade.php @@ -0,0 +1,3 @@ +
+ {{ $slot }} +
diff --git a/resources/views/components/modal/title.blade.php b/resources/views/components/modal/title.blade.php new file mode 100644 index 0000000..8314024 --- /dev/null +++ b/resources/views/components/modal/title.blade.php @@ -0,0 +1,9 @@ +@props([ + 'border' => false, +]) + +
$border])> +

+ {{ $slot }} +

+
diff --git a/resources/views/event/partials/details.blade.php b/resources/views/event/partials/details.blade.php index 3b7a74c..e89813c 100644 --- a/resources/views/event/partials/details.blade.php +++ b/resources/views/event/partials/details.blade.php @@ -1,10 +1,9 @@ -
-

- {{ $event->meta->title ?? '(no title)' }} -

- -

+ + {{ $event->meta->title ?? '(no title)' }} + + +

{{ $start->format('l, F j, Y · g:i A') }} @unless ($start->equalTo($end))  –  @@ -15,13 +14,13 @@

@if ($event->meta->location) -

Where: {{ $event->meta->location }}

+

Where: {{ $event->meta->location }}

@endif @if ($event->meta->description) -
- {!! nl2br(e($event->meta->description)) !!} -
+
+ {!! nl2br(e($event->meta->description)) !!} +
@endif -
+