diff --git a/app/Http/Controllers/EventQuestionsController.php b/app/Http/Controllers/EventQuestionsController.php new file mode 100644 index 00000000..67ace573 --- /dev/null +++ b/app/Http/Controllers/EventQuestionsController.php @@ -0,0 +1,149 @@ +get('event_id'); + + // Get the event or display a 'not found' warning. + $event = Event::findOrFail($event_id); + + // Initialize an empty array for the question options. + $question_options = [ + (object)[ + 'name' => '', + ], + ]; + + return view('ManageEvent.Modals.EditQuestion', [ + 'form_url' => route('event.question.store', [ + 'event_id' => $event_id, + ]), + 'event' => $event, + 'question' => [], + 'modal_id' => $request->get('modal_id'), + 'question_types' => QuestionType::all(), + 'question_options' => $question_options, + ]); + } + + /** + * Store a newly created resource in storage. + * + * @access public + * @param StoreEventQuestionRequest $request + * @return \Illuminate\Http\Response + */ + public function store(StoreEventQuestionRequest $request) + { + // Get the event ID. + $event_id = $request->get('event_id'); + + // Get the event or display a 'not found' warning. + $event = Event::findOrFail($event_id); + + // Create question. + $question = Question::createNew(false, false, true); + $question->title = $request->get('title'); + $question->instructions = $request->get('instructions'); + $question->is_required = $request->get('title'); + $question->question_type_id = $request->get('question_type_id'); + $question->save(); + + // Get options. + $options = $request->get('option'); + + // Add options. + if ($options && is_array($options)) { + foreach ($options as $option_name) { + if (trim($option_name) !== '') { + $question->options()->create([ + 'name' => $option_name, + ]); + } + } + } + + // Get tickets. + $ticket_ids = $request->get('tickets'); + + // Add ticket <-> question entry. + if ($ticket_ids && is_array($ticket_ids)) { + foreach ($ticket_ids as $ticket_id) { + Ticket::find($ticket_id)->questions()->attach($question->id); + } + } + + $event->questions()->attach($question->id); + + return response()->json([ + 'status' => 'success', + 'message' => 'Successfully Created Question. Refreshing page...', + 'runThis' => 'reloadPageDelayed();', + ]); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function show($id) + { + // + } + + /** + * Show the form for editing the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function edit($id) + { + // + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $id) + { + // + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy($id) + { + // + } +} \ No newline at end of file diff --git a/app/Http/Controllers/MyBaseController.php b/app/Http/Controllers/MyBaseController.php index 6ec2847f..e19edc6f 100644 --- a/app/Http/Controllers/MyBaseController.php +++ b/app/Http/Controllers/MyBaseController.php @@ -36,8 +36,11 @@ class MyBaseController extends Controller */ public function getEventViewData($event_id, $additional_data = []) { + $event = Event::scope()->findOrFail($event_id); + return array_merge([ - 'event' => Event::scope()->findOrFail($event_id), - ], $additional_data); + 'event' => $event, + 'questions' => $event->questions()->get(), + ], $additional_data); } } diff --git a/app/Http/Requests/StoreEventQuestionRequest.php b/app/Http/Requests/StoreEventQuestionRequest.php new file mode 100644 index 00000000..130983b2 --- /dev/null +++ b/app/Http/Requests/StoreEventQuestionRequest.php @@ -0,0 +1,31 @@ + 'required', + 'option' => 'array', + ]; + } +} diff --git a/app/Http/routes.php b/app/Http/routes.php index f9233ea2..5b43fedf 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -375,6 +375,11 @@ Route::group(['middleware' => ['auth', 'first.run']], function () { 'uses' => 'EventTicketQuestionsController@postCreateQuestion', ]); + /** + * Event questions. + */ + Route::resource('question', 'EventQuestionsController'); + /* * ------- * Attendees diff --git a/app/Models/Question.php b/app/Models/Question.php index 91ab4e7d..a50eb1a6 100644 --- a/app/Models/Question.php +++ b/app/Models/Question.php @@ -16,6 +16,7 @@ class Question extends MyBaseModel /** * The events associated with the question. * + * @access public * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function events() @@ -26,10 +27,22 @@ class Question extends MyBaseModel /** * The type associated with the question. * + * @access public * @return \Illuminate\Database\Eloquent\Relations\HasOne */ public function question_types() { return $this->hasOne('\App\Models\QuestionType'); } + + /** + * The options associated with the question. + * + * @access public + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function options() + { + return $this->hasMany('\App\Models\QuestionOption'); + } } diff --git a/app/Models/QuestionOption.php b/app/Models/QuestionOption.php new file mode 100644 index 00000000..b5af3674 --- /dev/null +++ b/app/Models/QuestionOption.php @@ -0,0 +1,35 @@ +belongsTo('\App\Models\Question'); + } +} diff --git a/app/Models/Ticket.php b/app/Models/Ticket.php index 3a869cf1..94716859 100644 --- a/app/Models/Ticket.php +++ b/app/Models/Ticket.php @@ -61,7 +61,7 @@ class Ticket extends MyBaseModel */ public function questions() { - return $this->belongsToMany('\App\Models\Question', 'ticket_question'); + return $this->belongsToMany('\App\Models\Question'); } /** diff --git a/database/migrations/2016_03_26_103318_create_attendees_questions.php b/database/migrations/2016_03_26_103318_create_attendees_questions.php new file mode 100644 index 00000000..f9f1eaf7 --- /dev/null +++ b/database/migrations/2016_03_26_103318_create_attendees_questions.php @@ -0,0 +1,113 @@ +increments('id'); + $table->string('alias'); + $table->string('name'); + $table->boolean('has_options')->default(false); + $table->boolean('allow_multiple')->default(false); + }); + + /** + * The questions. + */ + Schema::create('questions', function (Blueprint $table) + { + $table->increments('id'); + + $table->string('title', 255); + $table->text('instructions'); + + $table->unsignedInteger('question_type_id'); + $table->unsignedInteger('account_id')->index(); + + $table->tinyInteger('is_required')->default(0); + + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('question_type_id')->references('id')->on('question_types'); + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + }); + + /** + * Used for the questions that allow options (checkbox, radio, dropdown). + */ + Schema::create('question_options', function (Blueprint $table) + { + $table->increments('id'); + $table->string('name'); + $table->integer('question_id')->unsigned()->index(); + + $table->foreign('question_id')->references('id')->on('questions')->onDelete('cascade'); + }); + + /** + * Event / Question pivot table. + */ + Schema::create('event_question', function(Blueprint $table) + { + $table->increments('id'); + $table->integer('event_id')->unsigned()->index(); + $table->integer('question_id')->unsigned()->index(); + + $table->foreign('event_id')->references('id')->on('events')->onDelete('cascade'); + $table->foreign('question_id')->references('id')->on('questions')->onDelete('cascade'); + }); + + /** + * Question / Ticket pivot table. + */ + Schema::create('question_ticket', function (Blueprint $table) + { + $table->increments('id'); + $table->integer('question_id')->unsigned()->index(); + $table->integer('ticket_id')->unsigned()->index(); + + $table->foreign('ticket_id')->references('id')->on('tickets')->onDelete('cascade'); + $table->foreign('question_id')->references('id')->on('questions')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @access public + * @return void + */ + public function down() + { + $tables = [ + 'question_types', + 'questions', + 'question_options', + 'event_question', + 'question_ticket', + ]; + + DB::statement('SET FOREIGN_KEY_CHECKS=0;'); + + foreach ($tables as $table) { + Schema::drop($table); + } + + DB::statement('SET FOREIGN_KEY_CHECKS=1;'); + } +} diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 6104c4b3..03c4e0bc 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -19,5 +19,8 @@ class DatabaseSeeder extends Seeder // $this->call('UserTableSeeder'); $this->call('CountriesSeeder'); $this->command->info('Seeded the countries!'); + + $this->call('QuestionTypesSeeder'); + $this->command->info('Seeded the question types!'); } } diff --git a/database/seeds/QuestionTypesSeeder.php b/database/seeds/QuestionTypesSeeder.php new file mode 100644 index 00000000..0603987e --- /dev/null +++ b/database/seeds/QuestionTypesSeeder.php @@ -0,0 +1,60 @@ +insert([ + [ + 'id' => 1, + 'alias' => 'text', + 'name' => 'Single-line text box', + 'has_options' => 0, + 'allow_multiple' => 0, + ], + [ + 'id' => 2, + 'alias' => 'textarea', + 'name' => 'Multi-line text box', + 'has_options' => 0, + 'allow_multiple' => 0, + ], + [ + 'id' => 3, + 'alias' => 'dropdown', + 'name' => 'Dropdown (single selection)', + 'has_options' => 1, + 'allow_multiple' => 0, + ], + [ + 'id' => 4, + 'alias' => 'dropdown_multiple', + 'name' => 'Dropdown (multiple selection)', + 'has_options' => 1, + 'allow_multiple' => 1, + ], + [ + 'id' => 5, + 'alias' => 'checkbox', + 'name' => 'Checkbox', + 'has_options' => 1, + 'allow_multiple' => 1, + ], + [ + 'id' => 6, + 'alias' => 'radio', + 'name' => 'Radio input', + 'has_options' => 1, + 'allow_multiple' => 0, + ], + ]); + } +} diff --git a/public/assets/javascript/backend.js b/public/assets/javascript/backend.js index 528cef67..989de894 100644 --- a/public/assets/javascript/backend.js +++ b/public/assets/javascript/backend.js @@ -8550,6 +8550,12 @@ $(function () { }, error: function (data, statusText, xhr, $form) { + // Form validation error. + if (422 == data.status) { + processFormErrors($form, $.parseJSON(data.responseText)); + return; + } + showMessage('Whoops!, it looks like something went wrong on our servers.\n\ Please try again, or contact support if the problem persists.'); @@ -8589,24 +8595,7 @@ $(function () { break; case 'error': - $.each(data.messages, function (index, error) { - var $input = $(':input[name=' + index + ']', $form); - - if ($input.prop('type') === 'file') { - $('#input-' + $input.prop('name')).append('
| {{ $question->title }} | +