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