diff --git a/app/Http/Controllers/Admin/SiteDataController.php b/app/Http/Controllers/Admin/SiteDataController.php new file mode 100644 index 0000000..491976f --- /dev/null +++ b/app/Http/Controllers/Admin/SiteDataController.php @@ -0,0 +1,62 @@ +get(); + $dataText = SiteDataItem::where('type', 'text')->get(); + + $officerText = $this->officerText(siteData('officers')); + $concertEnsemblesText = $this->ensemblesText(siteData('concertEnsembles')); + $jazzEnsemblesText = $this->ensemblesText(siteData('jazzEnsembles')); + $beginnerEnsemblesText = $this->ensemblesText(siteData('beginnerEnsembles')); + + return view('admin.site-data', compact( + 'dataStrings', + 'dataText', + 'officerText', + 'concertEnsemblesText', + 'jazzEnsemblesText', + 'beginnerEnsemblesText' + )); + } + + public function update(SiteDataRequest $request) + { + foreach ($request->validated() as $key => $value) { + siteData($key, $value); + } + + return redirect()->route('admin.site-data.index')->with('success', 'Data updated successfully.'); + } + + protected function officerText(array $officerDataArray): string + { + $officerText = ''; + foreach ($officerDataArray as $officer) { + $officerText .= $officer['office'].', '.$officer['name'].', '.$officer['school'].PHP_EOL; + } + + return $officerText; + } + + protected function ensemblesText(array $ensembleDataArray): string + { + $ensembleText = ''; + foreach ($ensembleDataArray as $ensemble) { + $ensembleText .= $ensemble['name'].', '.$ensemble['chair'].', '.$ensemble['clinician'].PHP_EOL; + } + + return $ensembleText; + } +} diff --git a/app/Http/Requests/SiteDataRequest.php b/app/Http/Requests/SiteDataRequest.php new file mode 100644 index 0000000..8cd9d16 --- /dev/null +++ b/app/Http/Requests/SiteDataRequest.php @@ -0,0 +1,99 @@ +merge([ + 'officers' => $this->parseOfficerText($this->input('officers', '')), + 'concertEnsembles' => $this->parseEnsembleText($this->input('concertEnsembles', '')), + 'beginnerEnsembles' => $this->parseEnsembleText($this->input('beginnerEnsembles', '')), + 'jazzEnsembles' => $this->parseEnsembleText($this->input('jazzEnsembles', '')), + ]); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ + public function rules(): array + { + return [ + 'concertAuditionFee' => ['required', 'string'], + 'concertClinicDates' => ['required', 'string'], + 'concertClinicLocation' => ['required', 'string'], + 'beginnerClinicDates' => ['required', 'string'], + 'beginnerClinicLocation' => ['required', 'string'], + 'concertAuditionDate' => ['required', 'string'], + 'concertAuditionLocation' => ['required', 'string'], + 'concertEntryDeadline' => ['required', 'string'], + 'beginnerEntryDeadline' => ['required', 'string'], + 'concertAuditionAdditionalInformation' => ['required', 'string'], + 'beginnerAuditionAdditionalInformation' => ['required', 'string'], + 'officers' => ['required', 'array'], + 'officers.*.office' => ['required', 'string'], + 'officers.*.name' => ['required', 'string'], + 'officers.*.school' => ['required', 'string'], + 'concertEnsembles' => ['required', 'array'], + 'concertEnsembles.*.name' => ['required', 'string'], + 'concertEnsembles.*.chair' => ['required', 'string'], + 'concertEnsembles.*.clinician' => ['required', 'string'], + 'jazzEnsembles' => ['required', 'array'], + 'jazzEnsembles.*.name' => ['required', 'string'], + 'jazzEnsembles.*.chair' => ['required', 'string'], + 'jazzEnsembles.*.clinician' => ['required', 'string'], + 'beginnerEnsembles' => ['required', 'array'], + 'beginnerEnsembles.*.name' => ['required', 'string'], + 'beginnerEnsembles.*.chair' => ['required', 'string'], + 'beginnerEnsembles.*.clinician' => ['required', 'string'], + + ]; + } + + protected function parseOfficerText(string $text): array + { + $lines = explode(PHP_EOL, trim($text)); + $officers = []; + + foreach ($lines as $line) { + $parts = array_map('trim', explode(',', $line)); + $officers[] = [ + 'office' => $parts[0] ?? 'TBA', + 'name' => $parts[1] ?? 'TBA', + 'school' => $parts[2] ?? 'TBA', + ]; + } + + return $officers; + } + + protected function parseEnsembleText(string $text): array + { + $lines = explode(PHP_EOL, trim($text)); + $ensembles = []; + + foreach ($lines as $line) { + $parts = array_map('trim', explode(',', $line)); + $ensembles[] = [ + 'name' => $parts[0] ?? 'TBA', + 'chair' => $parts[1] ?? 'TBA', + 'clinician' => $parts[2] ?? 'TBA', + ]; + } + + return $ensembles; + } +} diff --git a/app/Models/SiteDataItem.php b/app/Models/SiteDataItem.php index 325a5e9..4d91c56 100644 --- a/app/Models/SiteDataItem.php +++ b/app/Models/SiteDataItem.php @@ -12,5 +12,5 @@ class SiteDataItem extends Model protected $keyType = 'string'; - protected $fillable = ['key', 'value', 'type']; + protected $fillable = ['key', 'value', 'type', 'description']; } diff --git a/app/View/Components/Layout/Admin.php b/app/View/Components/Layout/Admin.php index ffd2949..9e7ae40 100644 --- a/app/View/Components/Layout/Admin.php +++ b/app/View/Components/Layout/Admin.php @@ -27,7 +27,11 @@ class Admin extends Component [ 'name' => 'Users', 'link' => route('admin.users.index'), - ] + ], + [ + 'name' => 'Site Data', + 'link' => route('admin.site-data.index'), + ], ]; } diff --git a/config/siteData.php b/config/siteData.php index fffa6c7..709151f 100644 --- a/config/siteData.php +++ b/config/siteData.php @@ -26,78 +26,93 @@ return [ 'defaults' => [ 'concertClinicDates' => [ 'key' => 'concertClinicDates', + 'description' => 'Concert Clinic Dates', 'value' => 'UNSPECIFIED DATE', 'type' => 'string', ], 'concertClinicLocation' => [ 'key' => 'concertClinicLocation', + 'description' => 'Concert Clinic Location', 'value' => 'UNSPECIFIED SITE', 'type' => 'string', ], 'beginnerClinicDates' => [ 'key' => 'beginnerClinicDates', + 'description' => 'Beginner Clinic Dates', 'value' => 'UNSPECIFIED DATE', 'type' => 'string', ], 'beginnerClinicLocation' => [ 'key' => 'beginnerClinicLocation', + 'description' => 'Beginner Clinic Location', 'value' => 'UNSPECIFIED SITE', 'type' => 'string', ], 'concertAuditionDate' => [ 'key' => 'concertAuditionDate', + 'description' => 'Concert Audition Date', 'value' => 'UNSPECIFIED DATE', 'type' => 'string', ], 'concertAuditionLocation' => [ 'key' => 'concertAuditionLocation', + 'description' => 'Concert Audition Location', 'value' => 'UNSPECIFIED SITE', 'type' => 'string', ], 'concertEntryDeadline' => [ 'key' => 'concertEntryDeadline', + 'description' => 'Concert Entry Deadline', 'value' => 'UNSPECIFIED DATE', 'type' => 'string', ], 'beginnerEntryDeadline' => [ 'key' => 'beginnerEntryDeadline', + 'description' => 'Beginner Entry Deadline', 'value' => 'UNSPECIFIED DATE', 'type' => 'string', ], 'officers' => [ 'key' => 'officers', + 'description' => 'Officers', 'value' => '[{"office":"No Officers Defined","name":"No Officers Defined","school":" "}]', 'type' => 'json', ], 'concertEnsembles' => [ 'key' => 'concertEnsembles', + 'description' => 'Concert Ensembles', 'value' => '[{"name":"No Ensembles Defined","chair":" ","clinician":" "}]', 'type' => 'json', ], 'beginnerEnsembles' => [ 'key' => 'beginnerEnsembles', + 'description' => 'Beginner Ensembles', 'value' => '[{"name":"No Ensembles Defined","chair":" ","clinician":" "}]', 'type' => 'json', ], 'jazzEnsembles' => [ 'key' => 'jazzEnsembles', + 'description' => 'Jazz Ensembles', 'value' => '[{"name":"No Ensembles Defined","chair":" ","clinician":" "}]', 'type' => 'json', ], 'concertAuditionFee' => [ 'key' => 'concertAuditionFee', + 'description' => 'Concert Entry Fee', 'value' => 'NO FEE SET', 'type' => 'string', ], 'concertAuditionAdditionalInformation' => [ 'key' => 'concertAuditionAdditionalInformation', + 'description' => 'Additional information regarding concert auditions', 'value' => 'NO ADDITIONAL INFORMATION SET', - 'type' => 'string', + 'type' => 'text', ], 'beginnerAuditionAdditionalInformation' => [ 'key' => 'beginnerAuditionAdditionalInformation', + 'description' => 'Additional information regarding beginner nomination', 'value' => 'NO ADDITIONAL INFORMATION SET', - 'type' => 'string', - ] + 'type' => 'text', + ], ], ]; diff --git a/database/migrations/2025_12_13_151834_create_site_data_items_table.php b/database/migrations/2025_12_13_151834_create_site_data_items_table.php index 2cc4a86..2dfdd49 100644 --- a/database/migrations/2025_12_13_151834_create_site_data_items_table.php +++ b/database/migrations/2025_12_13_151834_create_site_data_items_table.php @@ -10,6 +10,7 @@ return new class extends Migration { Schema::create('site_data_items', function (Blueprint $table) { $table->string('key')->primary(); + $table->string('description'); $table->text('value'); $table->string('type'); $table->timestamps(); diff --git a/database/seeders/MeobdaData2526.php b/database/seeders/MeobdaData2526.php index 9889ef5..09841a9 100644 --- a/database/seeders/MeobdaData2526.php +++ b/database/seeders/MeobdaData2526.php @@ -10,17 +10,18 @@ class MeobdaData2526 extends Seeder public function run(): void { $defaults = [ - ['key' => 'concertAuditionFee', 'value' => '$10.00', 'type' => 'string'], - ['key' => 'concertClinicDates', 'value' => 'February 2-3, 2026', 'type' => 'string'], - ['key' => 'concertClinicLocation', 'value' => 'Oologah High School', 'type' => 'string'], - ['key' => 'beginnerClinicDates', 'value' => 'April 7, 2026', 'type' => 'string'], - ['key' => 'beginnerClinicLocation', 'value' => 'Wagoner High School', 'type' => 'string'], - ['key' => 'concertAuditionDate', 'value' => 'January 12, 2026', 'type' => 'string'], - ['key' => 'concertAuditionLocation', 'value' => 'Wagoner High School', 'type' => 'string'], - ['key' => 'concertEntryDeadline', 'value' => 'December 19, 2025', 'type' => 'string'], - ['key' => 'beginnerEntryDeadline', 'value' => 'March 13, 2026', 'type' => 'string'], + ['key' => 'concertAuditionFee', 'description' => 'Concert Entry Fee', 'value' => '$10.00', 'type' => 'string'], + ['key' => 'concertClinicDates', 'description' => 'Concert Clinic Dates', 'value' => 'February 2-3, 2026', 'type' => 'string'], + ['key' => 'concertClinicLocation', 'description' => 'Concert Clinic Location', 'value' => 'Oologah High School', 'type' => 'string'], + ['key' => 'beginnerClinicDates', 'description' => 'Beginner Clinic Dates', 'value' => 'April 7, 2026', 'type' => 'string'], + ['key' => 'beginnerClinicLocation', 'description' => 'Beginner Clinic Location', 'value' => 'Wagoner High School', 'type' => 'string'], + ['key' => 'concertAuditionDate', 'description' => 'Concert Audition Date', 'value' => 'January 12, 2026', 'type' => 'string'], + ['key' => 'concertAuditionLocation', 'description' => 'Concert Audition Location', 'value' => 'Wagoner High School', 'type' => 'string'], + ['key' => 'concertEntryDeadline', 'description' => 'Concert Entry Deadline', 'value' => 'December 19, 2025', 'type' => 'string'], + ['key' => 'beginnerEntryDeadline', 'description' => 'Beginner Entry Deadline', 'value' => 'March 13, 2026', 'type' => 'string'], [ 'key' => 'officers', + 'description' => 'Officers', 'value' => json_encode([ ['office' => 'President', 'name' => 'Keysto Stotz', 'school' => 'Skiatook'], ['office' => 'Vice President', 'name' => 'Jon Matthews', 'school' => 'Oologah'], @@ -31,6 +32,7 @@ class MeobdaData2526 extends Seeder ], [ 'key' => 'concertEnsembles', + 'description' => 'Concert Ensembles', 'value' => json_encode([ ['name' => 'High School Band', 'chair' => 'Bruce Thompson', 'clinician' => ''], ['name' => 'Junior High Band', 'chair' => 'Doug Finley', 'clinician' => ''], @@ -40,6 +42,7 @@ class MeobdaData2526 extends Seeder ], [ 'key' => 'beginnerEnsembles', + 'description' => 'Beginner Ensembles', 'value' => json_encode([ ['name' => 'First & Second Year A', 'chair' => 'Renee Roberts', 'clinician' => ''], ['name' => 'First & Second Year B', 'chair' => 'Madison West', 'clinician' => ''], @@ -49,6 +52,7 @@ class MeobdaData2526 extends Seeder ], [ 'key' => 'jazzEnsembles', + 'description' => 'Jazz Ensembles', 'value' => json_encode([ ['name' => 'Jazz Band', 'chair' => 'Eric Noble', 'clinician' => ''], ]), @@ -56,21 +60,23 @@ class MeobdaData2526 extends Seeder ], [ 'key' => 'concertAuditionAdditionalInformation', + 'description' => 'Additional information regarding concert auditions', 'value' => '9th Graders may audition for the Jr. High and/or HS Band. Those auditioning for both bands must pay a $10.00 audition fee for each instrument they audition on for each band. (A 9th grade trumpet player auditioning for the Jr. High and HS band would pay $20.00; a 9th grade sax player auditioning on alto and tenor for the Jr. High and HS band would pay $40.00). 9th Graders, auditioning for both Jr. High and HS, who score well enough to be in the HS band will be placed in the HS band.', - 'type' => 'string', + 'type' => 'text', ], [ 'key' => 'beginnerAuditionAdditionalInformation', + 'description' => 'Additional information regarding beginner nomination', 'value' => 'Students are selected by director recommendation. Directors may being up to 9 students for each band, but no more than one drummer or two alto saxes for either. Entry fee is $10.00 and includes lunch.', - 'type' => 'string', - ] + 'type' => 'text', + ], ]; foreach ($defaults as $item) { SiteDataItem::updateOrCreate( ['key' => $item['key']], - ['value' => $item['value'], 'type' => $item['type']] + ['description' => $item['description'], 'value' => $item['value'], 'type' => $item['type']] ); } } diff --git a/resources/views/admin/site-data.blade.php b/resources/views/admin/site-data.blade.php new file mode 100644 index 0000000..eb12911 --- /dev/null +++ b/resources/views/admin/site-data.blade.php @@ -0,0 +1,49 @@ + + @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + + Site Data + +
+ + @foreach($dataStrings as $dataItem) + + @endforeach + + @foreach($dataText as $dataItem) + {{ $dataItem->value }} + @endforeach + + + {{ $officerText }} + + + + {{ $concertEnsemblesText }} + + + + {{ $beginnerEnsemblesText }} + + + + {{ $jazzEnsemblesText }} + + +
+ Save Changes +
+ +
+
+
+
+
diff --git a/resources/views/components/form/textarea.blade.php b/resources/views/components/form/textarea.blade.php new file mode 100644 index 0000000..2d59969 --- /dev/null +++ b/resources/views/components/form/textarea.blade.php @@ -0,0 +1,10 @@ +@props(['name','id', 'label']) +
+ +
+ +
+ @error($name) +

{{ $message }}

+ @enderror +
diff --git a/resources/views/components/layout/admin.blade.php b/resources/views/components/layout/admin.blade.php index 4190063..76517fc 100644 --- a/resources/views/components/layout/admin.blade.php +++ b/resources/views/components/layout/admin.blade.php @@ -104,6 +104,21 @@
+ @if(session('success')) +
+
+
+ +
+
+

{{ session('success') }}

+
+
+
+ @endif +
{{ $slot }}
diff --git a/routes/web.php b/routes/web.php index 27f89a9..f454449 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,6 +1,7 @@ name( Route::middleware(['auth'])->prefix('admin')->name('admin.')->group(function () { Route::get('/', DashboardController::class)->name('dashboard'); + Route::prefix('/site-data')->name('site-data.')->group(function () { + Route::get('/', [SiteDataController::class, 'index'])->name('index'); + Route::patch('/', [SiteDataController::class, 'update'])->name('update'); + }); Route::prefix('/users')->name('users.')->group(function () { Route::get('/', [UsersController::class, 'index'])->name('index'); });