Skip to content

Commit

Permalink
early draft of results page
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilReinking committed Apr 2, 2022
1 parent b311de2 commit b5f46ca
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 38 deletions.
11 changes: 4 additions & 7 deletions app/Http/Controllers/Api/FormBlockController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,13 @@ public function index(Request $request, Form $form)

$blocks = $form->blocks->sortBy('sequence');

if (!$form->has_data_privacy) {
$blocks = $blocks->reject(function ($item) {
return $item->type === FormBlockType::consent;
if ($request->has('includeResults') && $request->input('includeResults') === 'true') {
$blocks->each(function ($block) {
$block->setAppends(['session_count']);
$block->interactions->each->setAppends(['responses_count']);
});
}

$blocks->each(function ($block) {
$block->interactions->each->setAppends(['responses_count']);
});

return response()->json($blocks->values()->toArray());
}

Expand Down
6 changes: 5 additions & 1 deletion app/Models/FormBlock.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,16 @@ public function getTypingDelayAttribute()
return $this->typingDelay();
}

public function getSessionCountAttribute()
{
return $this->responses()->selectRaw("COUNT(DISTINCT form_session_id) as count")->first()->count;
}

public function typingDelay()
{
return typingDelay($this->message);
}


public function getInteractionType(): FormBlockInteractionType | null
{
switch ($this->type) {
Expand Down
2 changes: 1 addition & 1 deletion app/Models/FormBlockInteraction.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class FormBlockInteraction extends Model
];

protected $hidden = [
'responses',
// 'responses',
];

protected static function boot()
Expand Down
1 change: 0 additions & 1 deletion database/factories/FormBlockFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ public function definition()
'uuid' => $this->faker->uuid,
'message' => $this->faker->sentence(10),
'type' => FormBlockType::none,
'responses' => null,
'sequence' => 0,
'webhook_url' => null,
'form_id' => Form::factory()
Expand Down
1 change: 1 addition & 0 deletions database/factories/FormBlockInteractionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public function definition()
return [
'uuid' => $this->faker->uuid(),
'type' => FormBlockInteractionType::button,
'label' => $this->faker->word,
'form_block_id' => FormBlock::factory(),
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public function up()
$table->text('message')->nullable();
$table->string('title', 1024)->nullable();
$table->longText('options')->nullable();
$table->text('responses')->nullable();
$table->string('uuid', 36);
$table->bigInteger('has_parent_interaction')->nullable();
$table->string('webhook_url')->nullable();
Expand Down
3 changes: 2 additions & 1 deletion database/seeders/DatabaseSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Database\Seeders\SimpleFormSeeder;

class DatabaseSeeder extends Seeder
{
Expand All @@ -13,6 +14,6 @@ class DatabaseSeeder extends Seeder
*/
public function run()
{
// \App\Models\User::factory(10)->create();
$this->call(SimpleFormSeeder::class);
}
}
125 changes: 125 additions & 0 deletions database/seeders/SimpleFormSeeder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

namespace Database\Seeders;

use App\Models\Form;
use App\Models\User;
use App\Models\FormBlock;
use App\Models\FormSession;
use Illuminate\Support\Str;
use App\Enums\FormBlockType;
use Illuminate\Database\Seeder;
use App\Models\FormBlockInteraction;
use Illuminate\Database\Eloquent\Collection;

class SimpleFormSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$user = User::first();

$form = Form::factory()->create([
'name' => 'Simple Form',
'description' => 'This form is for testing purposes.',
'brand_color' => '#000000',
'user_id' => $user ? $user->id : User::factory()->create()->id,
]);

$sessions = FormSession::factory(5)->create([
'form_id' => $form
]);

FormBlock::factory()->create([
'message' => 'Block with no message',
'form_id' => $form->id,
]);

$this->buildCheckbox($form, $sessions);
$this->buildRadio($form, $sessions);
$this->buildInput($form, $sessions, FormBlockType::short);
$this->buildInput($form, $sessions, FormBlockType::number);
$this->buildInput($form, $sessions, FormBlockType::email);
$this->buildInput($form, $sessions, FormBlockType::phone);
$this->buildInput($form, $sessions, FormBlockType::link);
}

public function buildCheckbox(Form $form, Collection $sessions)
{
// build checkbox block
$block = FormBlock::factory()->create([
'form_id' => $form->id,
'type' => FormBlockType::checkbox,
'message' => 'Checkbox block',
]);

$checkboxInteractions = FormBlockInteraction::factory(4)->create([
'type' => $block->getInteractionType(),
'form_block_id' => $block->id,
]);

$sessions->each(function ($session) use ($block, $checkboxInteractions) {
for ($i = rand(1, 3); $i > 0; $i--) {
$action = $checkboxInteractions->shuffle()->shift();

$session->responses()->create([
'value' => $action->label,
'form_block_id' => $block->id,
'form_block_interaction_id' => $action->id,
]);
}
});
}

public function buildRadio(Form $form, Collection $sessions)
{
// build checkbox block
$block = FormBlock::factory()->create([
'form_id' => $form->id,
'type' => FormBlockType::radio,
'message' => 'Radio block',
]);

$checkboxInteractions = FormBlockInteraction::factory(4)->create([
'type' => $block->getInteractionType(),
'form_block_id' => $block->id,
]);

$sessions->each(function ($session) use ($block, $checkboxInteractions) {
$action = $checkboxInteractions->shuffle()->shift();

$session->responses()->create([
'value' => $action->label,
'form_block_id' => $block->id,
'form_block_interaction_id' => $action->id,
]);
});
}

public function buildInput(Form $form, Collection $sessions, FormBlockType $type)
{
// build checkbox block
$block = FormBlock::factory()->create([
'form_id' => $form->id,
'type' => $type,
'message' => $type->value . ' block',
]);

$action = FormBlockInteraction::factory()->create([
'type' => $block->getInteractionType(),
'form_block_id' => $block->id,
]);

$sessions->each(function ($session) use ($block, $action) {
$session->responses()->create([
'value' => Str::random(16),
'form_block_id' => $block->id,
'form_block_interaction_id' => $action->id,
]);
});
}
}
14 changes: 9 additions & 5 deletions resources/js/Pages/Forms/Results.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<template>
<app-layout title="Results" limit-height>
<div class="w-full max-w-screen-lg py-6 text-left">
<h3 class="text-slate-900 text-xl font-bold">Results</h3>
<app-layout title="Results">
<div class="w-full max-w-5xl px-4 pb-8 text-left">
<FormSummary
class="mt-6"
v-bind="{ form, blocks: store.blocks || undefined }"
/>

<div class="mt-6 space-y-4">
<div class="mt-6 space-y-6">
<BlockResultItem
:block="block"
v-for="block in store.blocks"
Expand All @@ -24,6 +27,7 @@
import AppLayout from "@/Layouts/AppLayout.vue";
import { useForm } from "@/stores";
import { onMounted, onUnmounted } from "vue";
import FormSummary from "@/components/Factory/FormSummary.vue";
import BlockResultItem from "@/components/Factory/Results/BlockResultItem.vue";
import EmptyState from "@/components/EmptyState.vue";
Expand All @@ -37,7 +41,7 @@ onUnmounted(() => {
});
onMounted(async () => {
await Promise.all([store.getBlocks(), store.getFormBlockMapping()]);
await Promise.all([store.getBlocks(true), store.getFormBlockMapping()]);
});
store.$patch({
Expand Down
10 changes: 8 additions & 2 deletions resources/js/api/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@ import { AxiosResponse } from "axios";
import handler from "./handler";

export function callGetFormBlocks(
id: number
id: number,
includeResults = false
): Promise<AxiosResponse<FormBlockModel[]>> {
return new Promise(async (resolve, reject) => {
try {
const response = await handler.get(
window.route("api.blocks.index", { form: id })
window.route("api.blocks.index", { form: id }),
{
params: {
includeResults,
},
}
);

resolve(response as AxiosResponse<FormBlockModel[]>);
Expand Down
18 changes: 16 additions & 2 deletions resources/js/components/Factory/Results/BlockResultItem.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
<template>
<div class="overflow-hidden rounded-lg bg-white shadow">
<div
class="overflow-hidden rounded-lg bg-white shadow"
v-if="block.session_count !== 0"
>
<div class="px-4 py-5 sm:px-6">
<span class="font-mono text-xs text-grey-600">{{
block.title ?? block.uuid
}}</span>
<h4 class="text-lg font-medium" v-html="block.message"></h4>
</div>
<div class="px-4 py-5 sm:p-6">
<pre class="text-xs">{{ activeInteractions }}</pre>
<div class="mb-4 border-b border-grey-200 py-2 font-medium">
{{ block.session_count }} responses
</div>

<div
class="grid grid-cols-2 gap-x-6"
v-for="action in activeInteractions"
:key="action.id"
>
<div class="text-right">{{ action.label }}</div>
<div class="font-bold">{{ action.responses_count }}</div>
</div>
</div>
</div>
</template>
Expand Down
7 changes: 5 additions & 2 deletions resources/js/stores/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,15 @@ export const useForm = defineStore("form", {
this.mapping = response.data.mapping;
},

async getBlocks() {
async getBlocks(includeResults = false) {
if (!this.form) {
return;
}

const response = await callGetFormBlocks(this.form.id);
const response = await callGetFormBlocks(
this.form.id,
includeResults
);

this.blocks = response.data;
},
Expand Down
27 changes: 12 additions & 15 deletions tests/Feature/Forms/BlockTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use App\Enums\FormBlockType;
use App\Events\FormBlocksUpdated;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Testing\WithFaker;
use Database\Seeders\SimpleFormSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

class BlockTest extends TestCase
Expand Down Expand Up @@ -67,24 +67,21 @@ public function can_get_blocks_related_to_a_form()
}

/** @test */
public function can_get_blocks_related_to_a_form_with_consent_block()
public function can_get_blocks_with_results_loaded()
{
$form = Form::factory()->create(['has_data_privacy' => true]);

FormBlock::factory()->create([
'form_id' => $form->id,
'type' => FormBlockType::consent,
]);

FormBlock::factory()->count(5)->create([
'form_id' => $form->id,
]);
$this->seed(SimpleFormSeeder::class);
$form = Form::first();

$response = $this->actingAs($form->user)
->json('get', route('api.blocks.index', $form->id));
->json('get', route('api.blocks.index', $form->id), [
'includeResults' => 'true',
]);

$response->assertStatus(200);
$this->assertCount(6, $response->json());
$this->assertEquals(5, $response->json('1.session_count'));
$this->assertEquals(5, $response->json('2.session_count'));
$this->assertEquals(5, $response->json('3.session_count'));
$this->assertNotNull($response->json('1.interactions.0.responses_count'));
$this->assertNotNull($response->json('2.interactions.0.responses_count'));
}

/** @test */
Expand Down

0 comments on commit b5f46ca

Please sign in to comment.