feat: add mood tracking (monicahq/chandler#386)

This commit is contained in:
Mazarin
2023-01-21 23:14:44 +00:00
committed by GitHub
parent de04fbab63
commit 44862a5b3f
49 changed files with 1989 additions and 48 deletions
@@ -0,0 +1,38 @@
<?php
namespace App\Domains\Contact\ManageContactFeed\Web\ViewHelpers\Actions;
use App\Helpers\DateHelper;
use App\Models\ContactFeedItem;
use App\Models\User;
class ActionFeedMoodTrackingEvent
{
public static function data(ContactFeedItem $item, User $user): array
{
$contact = $item->contact;
$moodTrackingEvent = $item->feedable;
return [
'mood_tracking_event' => [
'object' => $moodTrackingEvent ? [
'id' => $moodTrackingEvent->id,
'rated_at' => DateHelper::format($moodTrackingEvent->rated_at, $user),
'note' => $moodTrackingEvent->note,
'number_of_hours_slept' => $moodTrackingEvent->number_of_hours_slept,
] : null,
'description' => $item->description,
],
'contact' => [
'id' => $contact->id,
'name' => $contact->name,
'age' => $contact->age,
'avatar' => $contact->avatar,
'url' => route('contact.show', [
'vault' => $contact->vault_id,
'contact' => $contact->id,
]),
],
];
}
}
@@ -7,6 +7,7 @@ use App\Domains\Contact\ManageContactFeed\Web\ViewHelpers\Actions\ActionFeedCont
use App\Domains\Contact\ManageContactFeed\Web\ViewHelpers\Actions\ActionFeedGenericContactInformation;
use App\Domains\Contact\ManageContactFeed\Web\ViewHelpers\Actions\ActionFeedGoal;
use App\Domains\Contact\ManageContactFeed\Web\ViewHelpers\Actions\ActionFeedLabelAssigned;
use App\Domains\Contact\ManageContactFeed\Web\ViewHelpers\Actions\ActionFeedMoodTrackingEvent;
use App\Domains\Contact\ManageContactFeed\Web\ViewHelpers\Actions\ActionFeedPet;
use App\Helpers\DateHelper;
use App\Helpers\UserHelper;
@@ -92,6 +93,11 @@ class ModuleFeedViewHelper
case 'goal_destroyed':
return ActionFeedGoal::data($item);
case 'mood_tracking_event_added':
case 'mood_tracking_event_updated':
case 'mood_tracking_event_deleted':
return ActionFeedMoodTrackingEvent::data($item, $user);
default:
return ActionFeedGenericContactInformation::data($item);
}
@@ -0,0 +1,89 @@
<?php
namespace App\Domains\Contact\ManageMoodTrackingEvents\Services;
use App\Interfaces\ServiceInterface;
use App\Models\ContactFeedItem;
use App\Models\MoodTrackingEvent;
use App\Services\BaseService;
use Carbon\Carbon;
class CreateMoodTrackingEvent extends BaseService implements ServiceInterface
{
private MoodTrackingEvent $moodTrackingEvent;
/**
* Get the validation rules that apply to the service.
*
* @return array
*/
public function rules(): array
{
return [
'account_id' => 'required|integer|exists:accounts,id',
'vault_id' => 'required|integer|exists:vaults,id',
'author_id' => 'required|integer|exists:users,id',
'contact_id' => 'required|integer|exists:contacts,id',
'mood_tracking_parameter_id' => 'required|integer|exists:mood_tracking_parameters,id',
'rated_at' => 'required|date_format:Y-m-d',
'note' => 'nullable|string|max:65535',
'number_of_hours_slept' => 'nullable|integer',
];
}
/**
* Get the permissions that apply to the user calling the service.
*
* @return array
*/
public function permissions(): array
{
return [
'author_must_belong_to_account',
'vault_must_belong_to_account',
'author_must_be_vault_editor',
'contact_must_belong_to_vault',
];
}
/**
* Create a mood tracking event.
*
* @param array $data
* @return MoodTrackingEvent
*/
public function execute(array $data): MoodTrackingEvent
{
$this->validateRules($data);
$this->vault->moodTrackingParameters()
->findOrFail($data['mood_tracking_parameter_id']);
$this->moodTrackingEvent = MoodTrackingEvent::create([
'contact_id' => $this->contact->id,
'mood_tracking_parameter_id' => $data['mood_tracking_parameter_id'],
'rated_at' => $data['rated_at'],
'note' => $this->valueOrNull($data, 'note'),
'number_of_hours_slept' => $this->valueOrNull($data, 'number_of_hours_slept'),
]);
$this->contact->last_updated_at = Carbon::now();
$this->contact->save();
$this->createFeedItem();
return $this->moodTrackingEvent;
}
private function createFeedItem(): void
{
$feedItem = ContactFeedItem::create([
'author_id' => $this->author->id,
'contact_id' => $this->contact->id,
'action' => ContactFeedItem::ACTION_MOOD_TRACKING_EVENT_CREATED,
'description' => $this->moodTrackingEvent->moodTrackingParameter->label,
]);
$this->moodTrackingEvent->feedItem()->save($feedItem);
}
}
@@ -0,0 +1,75 @@
<?php
namespace App\Domains\Contact\ManageMoodTrackingEvents\Services;
use App\Interfaces\ServiceInterface;
use App\Models\ContactFeedItem;
use App\Models\MoodTrackingEvent;
use App\Services\BaseService;
use Carbon\Carbon;
class DestroyMoodTrackingEvent extends BaseService implements ServiceInterface
{
private MoodTrackingEvent $moodTrackingEvent;
/**
* Get the validation rules that apply to the service.
*
* @return array
*/
public function rules(): array
{
return [
'account_id' => 'required|integer|exists:accounts,id',
'vault_id' => 'required|integer|exists:vaults,id',
'author_id' => 'required|integer|exists:users,id',
'contact_id' => 'required|integer|exists:contacts,id',
'mood_tracking_event_id' => 'required|integer|exists:mood_tracking_events,id',
];
}
/**
* Get the permissions that apply to the user calling the service.
*
* @return array
*/
public function permissions(): array
{
return [
'author_must_belong_to_account',
'vault_must_belong_to_account',
'contact_must_belong_to_vault',
'author_must_be_vault_editor',
];
}
/**
* Destroy a mood tracking event.
*
* @param array $data
*/
public function execute(array $data): void
{
$this->validateRules($data);
$this->moodTrackingEvent = $this->contact->moodTrackingEvents()
->findOrFail($data['mood_tracking_event_id']);
$this->moodTrackingEvent->delete();
$this->contact->last_updated_at = Carbon::now();
$this->contact->save();
$this->createFeedItem();
}
private function createFeedItem(): void
{
ContactFeedItem::create([
'author_id' => $this->author->id,
'contact_id' => $this->contact->id,
'action' => ContactFeedItem::ACTION_MOOD_TRACKING_EVENT_DESTROYED,
'description' => $this->moodTrackingEvent->moodTrackingParameter->label,
]);
}
}
@@ -0,0 +1,92 @@
<?php
namespace App\Domains\Contact\ManageMoodTrackingEvents\Services;
use App\Interfaces\ServiceInterface;
use App\Models\ContactFeedItem;
use App\Models\MoodTrackingEvent;
use App\Services\BaseService;
use Carbon\Carbon;
class UpdateMoodTrackingEvent extends BaseService implements ServiceInterface
{
private MoodTrackingEvent $moodTrackingEvent;
/**
* Get the validation rules that apply to the service.
*
* @return array
*/
public function rules(): array
{
return [
'account_id' => 'required|integer|exists:accounts,id',
'vault_id' => 'required|integer|exists:vaults,id',
'author_id' => 'required|integer|exists:users,id',
'contact_id' => 'required|integer|exists:contacts,id',
'mood_tracking_parameter_id' => 'required|integer|exists:mood_tracking_parameters,id',
'mood_tracking_event_id' => 'required|integer|exists:mood_tracking_events,id',
'rated_at' => 'required|date_format:Y-m-d',
'note' => 'nullable|string|max:65535',
'number_of_hours_slept' => 'nullable|integer',
];
}
/**
* Get the permissions that apply to the user calling the service.
*
* @return array
*/
public function permissions(): array
{
return [
'author_must_belong_to_account',
'vault_must_belong_to_account',
'contact_must_belong_to_vault',
'author_must_be_vault_editor',
];
}
/**
* Update a mood tracking event.
*
* @param array $data
* @return MoodTrackingEvent
*/
public function execute(array $data): MoodTrackingEvent
{
$this->validateRules($data);
$parameter = $this->vault->moodTrackingParameters()
->findOrFail($data['mood_tracking_parameter_id']);
$this->moodTrackingEvent = $this->contact->moodTrackingEvents()
->where('mood_tracking_parameter_id', $parameter->id)
->findOrFail($data['mood_tracking_event_id']);
$this->moodTrackingEvent->mood_tracking_parameter_id = $data['mood_tracking_parameter_id'];
$this->moodTrackingEvent->rated_at = $data['rated_at'];
$this->moodTrackingEvent->note = $this->valueOrNull($data, 'note');
$this->moodTrackingEvent->number_of_hours_slept = $this->valueOrNull($data, 'number_of_hours_slept');
$this->moodTrackingEvent->save();
$this->contact->last_updated_at = Carbon::now();
$this->contact->save();
$this->createFeedItem();
return $this->moodTrackingEvent;
}
private function createFeedItem(): void
{
$feedItem = ContactFeedItem::create([
'author_id' => $this->author->id,
'contact_id' => $this->contact->id,
'action' => ContactFeedItem::ACTION_MOOD_TRACKING_EVENT_UPDATED,
'description' => $this->moodTrackingEvent->moodTrackingParameter->label,
]);
$this->moodTrackingEvent->feedItem()->save($feedItem);
}
}
@@ -0,0 +1,39 @@
<?php
namespace App\Domains\Contact\ManageMoodTrackingEvents\Web\Controllers;
use App\Domains\Contact\ManageMoodTrackingEvents\Services\CreateMoodTrackingEvent;
use App\Domains\Vault\ManageVault\Web\ViewHelpers\VaultShowViewHelper;
use App\Http\Controllers\Controller;
use App\Models\Contact;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ContactMoodTrackingEventsController extends Controller
{
public function store(Request $request, int $vaultId, int $contactId): JsonResponse
{
$carbonDate = Carbon::parse($request->input('date'))->format('Y-m-d');
$data = [
'account_id' => Auth::user()->account_id,
'author_id' => Auth::id(),
'vault_id' => $vaultId,
'contact_id' => $contactId,
'mood_tracking_parameter_id' => $request->input('parameter_id'),
'rated_at' => $carbonDate,
'note' => $request->input('note') ?? null,
'number_of_hours_slept' => $request->input('hours') ?? null,
];
$moodTrackingEvent = (new CreateMoodTrackingEvent())->execute($data);
$contact = Contact::find($contactId);
return response()->json([
'data' => VaultShowViewHelper::dtoMoodTrackingEvent($moodTrackingEvent, Auth::user()),
], 201);
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Domains\Vault\ManageReports\Web\Controllers;
use App\Domains\Vault\ManageReports\Web\ViewHelpers\ReportIndexViewHelper;
use App\Domains\Vault\ManageVault\Web\ViewHelpers\VaultIndexViewHelper;
use App\Http\Controllers\Controller;
use App\Models\Vault;
use Illuminate\Http\Request;
use Inertia\Inertia;
class ReportIndexController extends Controller
{
public function index(Request $request, int $vaultId)
{
$vault = Vault::findOrFail($vaultId);
return Inertia::render('Vault/Reports/Index', [
'layoutData' => VaultIndexViewHelper::layoutData($vault),
'data' => ReportIndexViewHelper::data($vault),
]);
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Domains\Vault\ManageReports\Web\Controllers;
use App\Domains\Vault\ManageReports\Web\ViewHelpers\ReportMoodTrackingEventIndexViewHelper;
use App\Domains\Vault\ManageVault\Web\ViewHelpers\VaultIndexViewHelper;
use App\Http\Controllers\Controller;
use App\Models\Vault;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Inertia\Inertia;
class ReportMoodTrackingEventController extends Controller
{
public function index(Request $request, int $vaultId)
{
$vault = Vault::findOrFail($vaultId);
return Inertia::render('Vault/Reports/MoodTrackingEvents/Index', [
'layoutData' => VaultIndexViewHelper::layoutData($vault),
'data' => ReportMoodTrackingEventIndexViewHelper::data($vault, Auth::user(), Carbon::now()->year),
]);
}
}
@@ -10,7 +10,6 @@ use App\Models\ContactImportantDate;
use App\Models\User;
use App\Models\Vault;
use Carbon\Carbon;
use Illuminate\Support\Collection;
class ReportImportantDateSummaryIndexViewHelper
{
@@ -20,9 +19,9 @@ class ReportImportantDateSummaryIndexViewHelper
*
* @param Vault $vault
* @param User $user
* @return Collection
* @return array
*/
public static function data(Vault $vault, User $user): Collection
public static function data(Vault $vault, User $user): array
{
$contactsInVault = $vault->contacts->pluck('id')->toArray();
$importantDates = ContactImportantDate::whereIn('contact_id', $contactsInVault)
@@ -58,6 +57,13 @@ class ReportImportantDateSummaryIndexViewHelper
]);
}
return $monthsCollection;
return [
'months' => $monthsCollection,
'url' => [
'reports' => route('vault.reports.index', [
'vault' => $vault->id,
]),
],
];
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Domains\Vault\ManageReports\Web\ViewHelpers;
use App\Models\Vault;
class ReportIndexViewHelper
{
public static function data(Vault $vault): array
{
return [
'url' => [
'mood_tracking_events' => route('vault.reports.mood_tracking_events.index', [
'vault' => $vault->id,
]),
'important_date_summary' => route('vault.reports.important_dates.index', [
'vault' => $vault->id,
]),
],
];
}
}
@@ -0,0 +1,78 @@
<?php
namespace App\Domains\Vault\ManageReports\Web\ViewHelpers;
use App\Helpers\DateHelper;
use App\Models\User;
use App\Models\Vault;
use Carbon\CarbonImmutable;
use Illuminate\Support\Collection;
class ReportMoodTrackingEventIndexViewHelper
{
public static function data(Vault $vault, User $user, int $year): array
{
return [
'months' => self::year($vault, $user, $year),
'url' => [
'reports' => route('vault.reports.index', [
'vault' => $vault->id,
]),
],
];
}
/**
* Get all the mood tracking events for the given year
*
* @param Vault $vault
* @param User $user
* @param int $year
* @return Collection
*/
private static function year(Vault $vault, User $user, int $year): Collection
{
$contact = $user->getContactInVault($vault);
$moodTrackingEvents = $contact->moodTrackingEvents()
->with('moodTrackingParameter')
->whereYear('rated_at', (string) $year)
->orderBy('rated_at', 'asc')
->get();
// create the yearly calendar
$monthsCollection = collect();
for ($month = 1; $month < 13; $month++) {
$currentMonth = CarbonImmutable::create($year, $month, 1);
$daysCollection = collect();
for ($day = 1; $day < $currentMonth->daysInMonth; $day++) {
$date = CarbonImmutable::create($year, $month, $day);
$moodTrackingForTheDay = null;
foreach ($moodTrackingEvents as $moodTrackingEvent) {
if ($moodTrackingEvent->rated_at->month === $date->month &&
$moodTrackingEvent->rated_at->day === $date->day) {
$moodTrackingForTheDay = $moodTrackingEvent;
}
}
$daysCollection->push([
'id' => $day,
'event' => $moodTrackingForTheDay ? [
'id' => $moodTrackingForTheDay->id,
'hex_color' => $moodTrackingForTheDay->moodTrackingParameter->hex_color,
] : null,
]);
}
$monthsCollection->push([
'id' => $month,
'month_word' => DateHelper::formatMonthNumber($currentMonth),
'days' => $daysCollection,
]);
}
return $monthsCollection;
}
}
@@ -58,6 +58,7 @@ class VaultController extends Controller
'upcomingReminders' => VaultShowViewHelper::upcomingReminders($vault, Auth::user()),
'favorites' => VaultShowViewHelper::favorites($vault, Auth::user()),
'dueTasks' => VaultShowViewHelper::dueTasks($vault, Auth::user()),
'moodTrackingEvents' => VaultShowViewHelper::moodTrackingEvents($vault, Auth::user()),
'loadFeedUrl' => route('vault.feed.show', [
'vault' => $vaultId,
]),
@@ -3,6 +3,7 @@
namespace App\Domains\Vault\ManageVault\Web\ViewHelpers;
use App\Helpers\DateHelper;
use App\Models\MoodTrackingEvent;
use App\Models\User;
use App\Models\Vault;
use Carbon\Carbon;
@@ -155,4 +156,42 @@ class VaultShowViewHelper
],
];
}
public static function moodTrackingEvents(Vault $vault, User $user): array
{
// get available mood tracking parameters
$moodTrackingParametersCollection = $vault->moodTrackingParameters()
->orderBy('position', 'asc')
->get()
->map(fn ($moodTrackingParameter) => [
'id' => $moodTrackingParameter->id,
'label' => $moodTrackingParameter->label,
'hex_color' => $moodTrackingParameter->hex_color,
]);
return [
'mood_tracking_parameters' => $moodTrackingParametersCollection,
'current_date' => Carbon::now($user->timezone)->format('Y-m-d'),
'url' => [
'history' => route('vault.reports.mood_tracking_events.index', [
'vault' => $vault->id,
]),
'store' => route('contact.mood_tracking_event.store', [
'vault' => $vault->id,
'contact' => $user->getContactInVault($vault)->id,
]),
],
];
}
public static function dtoMoodTrackingEvent(MoodTrackingEvent $event, User $user): array
{
return [
'id' => $event->id,
'label' => $event->moodTrackingParameter->label,
'rated_at' => DateHelper::format($event->rated_at, $user),
'note' => $event->note,
'number_of_hours_slept' => $event->number_of_hours_slept,
];
}
}
+11
View File
@@ -148,6 +148,17 @@ class DateHelper
return $date->isoFormat(trans('format.day_number'));
}
/**
* Return the first letter of the month, like "Jan" for January.
*
* @param $date
* @return string
*/
public static function formatMonthNumber($date): string
{
return $date->isoFormat(trans('format.short_month'));
}
/**
* Return a collection of months.
*
+10
View File
@@ -386,6 +386,16 @@ class Contact extends Model
return $this->belongsToMany(LifeEvent::class, 'life_event_participants', 'contact_id', 'life_event_id');
}
/**
* Get the mood tracking events associated with the contact.
*
* @return HasMany
*/
public function moodTrackingEvents(): HasMany
{
return $this->hasMany(MoodTrackingEvent::class);
}
/**
* Get the addresses associated with the contact.
*
+6 -12
View File
@@ -64,18 +64,6 @@ class ContactFeedItem extends Model
public const ACTION_CONTACT_ADDRESS_DESTROYED = 'address_destroyed';
public const ACTION_CONTACT_EVENT_CREATED = 'added an event';
public const ACTION_CONTACT_EVENT_UPDATED = 'updated an event';
public const ACTION_CONTACT_EVENT_DESTROYED = 'deleted an event';
public const ACTION_CONTACT_ACTIVITY_CREATED = 'added an activity';
public const ACTION_CONTACT_ACTIVITY_UPDATED = 'updated an activity';
public const ACTION_CONTACT_ACTIVITY_DESTROYED = 'deleted an activity';
public const ACTION_LOAN_CREATED = 'loan_created';
public const ACTION_LOAN_UPDATED = 'loan_updated';
@@ -98,6 +86,12 @@ class ContactFeedItem extends Model
public const ACTION_CHANGE_AVATAR = 'changed_avatar';
public const ACTION_MOOD_TRACKING_EVENT_CREATED = 'mood_tracking_event_added';
public const ACTION_MOOD_TRACKING_EVENT_UPDATED = 'mood_tracking_event_updated';
public const ACTION_MOOD_TRACKING_EVENT_DESTROYED = 'mood_tracking_event_deleted';
/**
* The attributes that are mass assignable.
*
+67
View File
@@ -0,0 +1,67 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphOne;
class MoodTrackingEvent extends Model
{
use HasFactory;
protected $table = 'mood_tracking_events';
/**
* The attributes that are mass assignable.
*
* @var array<string>
*/
protected $fillable = [
'contact_id',
'mood_tracking_parameter_id',
'rated_at',
'note',
'number_of_hours_slept',
];
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = [
'rated_at',
];
/**
* Get the contact associated with the mood tracking event.
*
* @return BelongsTo
*/
public function contact(): BelongsTo
{
return $this->belongsTo(Contact::class);
}
/**
* Get the mood tracking parameter associated with the mood tracking event.
*
* @return BelongsTo
*/
public function moodTrackingParameter(): BelongsTo
{
return $this->belongsTo(MoodTrackingParameter::class);
}
/**
* Get the mood tracking event's feed item.
*
* @return MorphOne
*/
public function feedItem(): MorphOne
{
return $this->morphOne(ContactFeedItem::class, 'feedable');
}
}
+11
View File
@@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class MoodTrackingParameter extends Model
{
@@ -36,6 +37,16 @@ class MoodTrackingParameter extends Model
return $this->belongsTo(Vault::class);
}
/**
* Get the mood tracking events associated with the mood tracking parameter.
*
* @return HasMany
*/
public function moodTrackingEvents(): HasMany
{
return $this->hasMany(MoodTrackingEvent::class);
}
/**
* Get the label attribute.
* A mood tracking parameter has a default label that can be translated.
@@ -0,0 +1,32 @@
<?php
namespace Database\Factories;
use App\Models\Contact;
use App\Models\MoodTrackingEvent;
use App\Models\MoodTrackingParameter;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\MoodTrackingEvent>
*/
class MoodTrackingEventFactory extends Factory
{
protected $model = MoodTrackingEvent::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'contact_id' => Contact::factory(),
'mood_tracking_parameter_id' => MoodTrackingParameter::factory(),
'rated_at' => $this->faker->dateTime(),
'note' => $this->faker->name(),
'number_of_hours_slept' => $this->faker->randomNumber(),
];
}
}
@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('mood_tracking_events', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('contact_id');
$table->unsignedBigInteger('mood_tracking_parameter_id');
$table->datetime('rated_at');
$table->text('note')->nullable();
$table->integer('number_of_hours_slept')->nullable();
$table->timestamps();
$table->foreign('mood_tracking_parameter_id')->references('id')->on('mood_tracking_parameters')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('mood_tracking_events');
}
};
+1
View File
@@ -53,6 +53,7 @@ return [
'feed_item_favorited' => 'added the contact to the favorites',
'feed_item_unfavorited' => 'removed the contact from the favorites',
'feed_item_changed_avatar' => 'updated the avatar of the contact',
'feed_item_mood_tracking_event_added' => 'logged the mood',
/***************************************************************
* MODULE: GROUP
+3
View File
@@ -25,6 +25,9 @@ return [
/* short month and the year in a format like "July 2020" - see https://carbon.nesbot.com/docs/#iso-format-available-replacements */
'long_month_year' => 'MMMM Y',
/* month as a string like "Jul" - see https://carbon.nesbot.com/docs/#iso-format-available-replacements */
'short_month' => 'MMM',
/* day and month in a format like "July 29th" - see https://carbon.nesbot.com/docs/#iso-format-available-replacements */
'long_month_day' => 'MMMM Do',
+5 -5
View File
@@ -191,11 +191,11 @@ return [
'settings_delete_cta_confirmation' => 'Are you sure? This will delete all the data inside this vault.',
'settings_delete_destroy_success' => 'The vault has been deleted',
'settings_mood_tracking_parameters_awesome' => 'Awesome',
'settings_mood_tracking_parameters_good' => 'Good',
'settings_mood_tracking_parameters_meh' => 'Meh',
'settings_mood_tracking_parameters_bad' => 'Bad',
'settings_mood_tracking_parameters_awful' => 'Awful',
'settings_mood_tracking_parameters_awesome' => '🥳 Awesome',
'settings_mood_tracking_parameters_good' => '😀 Good',
'settings_mood_tracking_parameters_meh' => '😐 Meh',
'settings_mood_tracking_parameters_bad' => '😔 Bad',
'settings_mood_tracking_parameters_awful' => '😩 Awful',
'settings_life_event_category_transportation' => 'Transportation',
'settings_life_event_type_transportation_bike' => 'Rode a bike',
'settings_life_event_type_transportation_car' => 'Drove',
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

+8 -8
View File
@@ -156,49 +156,49 @@
<div class="flex flex-wrap text-xs">
<span
v-if="!showMiddleNameField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayMiddleNameField">
{{ $t('vault.create_contact_add_middle_name') }}
</span>
<span
v-if="!showPrefixField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayPrefixField">
{{ $t('vault.create_contact_add_prefix') }}
</span>
<span
v-if="!showSuffixField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displaySuffixField">
{{ $t('vault.create_contact_add_suffix') }}
</span>
<span
v-if="!showNicknameField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayNicknameField">
{{ $t('vault.create_contact_add_nickname') }}
</span>
<span
v-if="!showMaidenNameField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayMaidenNameField">
{{ $t('vault.create_contact_add_maiden_name') }}
</span>
<span
v-if="data.genders.length > 0 && !showGenderField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayGenderField">
{{ $t('vault.create_contact_add_gender') }}
</span>
<span
v-if="data.pronouns.length > 0 && !showPronounField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayPronounField">
{{ $t('vault.create_contact_add_pronoun') }}
</span>
<span
v-if="data.templates.length > 0 && !showTemplateField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayTemplateField">
{{ $t('vault.create_contact_add_change_template') }}
</span>
@@ -172,25 +172,25 @@
<div class="mb-4 flex flex-wrap text-xs">
<span
v-if="!showLastNameField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayLastNameField">
+ last name
</span>
<span
v-if="!showMiddleNameField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayMiddleNameField">
+ middle name
</span>
<span
v-if="!showNicknameField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayNicknameField">
+ nickname
</span>
<span
v-if="!showMaidenNameField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayMaidenNameField">
+ maiden name
</span>
@@ -288,13 +288,13 @@
<div class="flex flex-wrap text-xs">
<span
v-if="data.genders.length > 0 && !showGenderField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayGenderField">
+ gender
</span>
<span
v-if="data.pronouns.length > 0 && !showPronounField"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:text-gray-900"
class="mr-2 mb-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 hover:bg-slate-300 dark:bg-slate-500 dark:text-gray-900 dark:text-white"
@click="displayPronounField">
+ pronoun
</span>
@@ -41,6 +41,9 @@
<!-- right -->
<div class="p-3 sm:p-0">
<!-- mood tracking -->
<mood-tracking-events :data="moodTrackingEvents" />
<!-- upcoming reminders -->
<upcoming-reminders :data="upcomingReminders" />
@@ -59,6 +62,7 @@ import LastUpdated from '@/Pages/Vault/Dashboard/Partials/LastUpdated.vue';
import UpcomingReminders from '@/Pages/Vault/Dashboard/Partials/UpcomingReminders.vue';
import Favorites from '@/Pages/Vault/Dashboard/Partials/Favorites.vue';
import DueTasks from '@/Pages/Vault/Dashboard/Partials/DueTasks.vue';
import MoodTrackingEvents from '@/Pages/Vault/Dashboard/Partials/MoodTrackingEvents.vue';
import Feed from '@/Shared/Modules/Feed.vue';
export default {
@@ -69,6 +73,7 @@ export default {
Favorites,
DueTasks,
Feed,
MoodTrackingEvents,
},
props: {
@@ -96,6 +101,10 @@ export default {
type: Object,
default: null,
},
moodTrackingEvents: {
type: Object,
default: null,
},
},
};
</script>
@@ -81,7 +81,7 @@
<!-- blank state -->
<div
v-if="data.tasks.length == 0"
class="mb-6 flex items-center rounded-lg border border-gray-200 bg-white p-3 dark:border-gray-800 dark:bg-gray-900">
class="mb-2 flex items-center rounded-lg border border-gray-200 bg-white p-3 dark:border-gray-800 dark:bg-gray-900">
<img src="/img/dashboard_blank_tasks.svg" :alt="$t('Tasks')" class="mr-2 h-14 w-14" />
<p class="px-5 text-center">
{{ $t('vault.dashboard_due_tasks_blank') }}
@@ -0,0 +1,230 @@
<script setup>
import PrettySpan from '@/Shared/Form/PrettySpan.vue';
import TextArea from '@/Shared/Form/TextArea.vue';
import PrettyButton from '@/Shared/Form/PrettyButton.vue';
import TextInput from '@/Shared/Form/TextInput.vue';
import { useForm } from '@inertiajs/inertia-vue3';
import { onMounted, ref } from 'vue';
const props = defineProps({
data: Object,
});
const loadingState = ref('');
const createMoodEventModalShown = ref(false);
const datePickerFieldShown = ref(false);
const noteFieldShown = ref(false);
const hoursSleptFieldShown = ref(false);
const successShown = ref(false);
const form = useForm({
parameter_id: 0,
date: null,
hours: null,
note: null,
});
onMounted(() => {
form.date = props.data.current_date;
});
const showMoodEventModal = () => {
datePickerFieldShown.value = false;
noteFieldShown.value = false;
hoursSleptFieldShown.value = false;
createMoodEventModalShown.value = true;
form.note = '';
form.hours = null;
};
const showDatePickerField = () => {
datePickerFieldShown.value = true;
};
const showNoteField = () => {
noteFieldShown.value = true;
};
const showHoursSleptField = () => {
hoursSleptFieldShown.value = true;
};
const submit = () => {
loadingState.value = 'loading';
axios
.post(props.data.url.store, form)
.then(() => {
createMoodEventModalShown.value = false;
successShown.value = true;
loadingState.value = null;
})
.catch((error) => {
loadingState.value = null;
form.errors = error.response.data;
});
};
</script>
<template>
<div class="mb-10">
<h3 class="mb-3 border-b border-gray-200 pb-1 font-medium dark:border-gray-700">
<span class="relative">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="icon-sidebar relative inline h-4 w-4 text-gray-300 hover:text-gray-600 dark:text-gray-400 hover:dark:text-gray-400">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.042 21.672L13.684 16.6m0 0l-2.51 2.225.569-9.47 5.227 7.917-3.286-.672zM12 2.25V4.5m5.834.166l-1.591 1.591M20.25 10.5H18M7.757 14.743l-1.59 1.59M6 10.5H3.75m4.007-4.243l-1.59-1.59" />
</svg>
</span>
Record your mood
</h3>
<!-- cta -->
<div
v-if="!createMoodEventModalShown && !successShown"
class="mb-4 flex items-center rounded-lg border border-gray-200 bg-white p-3 dark:border-gray-700 dark:bg-gray-900">
<img src="/img/dashboard_blank_how_are_you.svg" :alt="$t('Reminders')" class="mr-2 h-14 w-14" />
<div class="mb-2 flex flex-col px-5">
<p class="mb-2">How are you?</p>
<pretty-button :text="'Record your mood'" @click="showMoodEventModal" />
</div>
</div>
<!-- add an event modal -->
<form
v-if="createMoodEventModalShown"
class="bg-form mb-6 rounded-lg border border-gray-200 dark:border-gray-700 dark:bg-gray-900"
@submit.prevent="submit()">
<div class="border-b border-gray-200 p-5 dark:border-gray-700">
<div v-if="form.errors.length > 0" class="p-5">
<errors :errors="form.errors" />
</div>
<!-- mood tracking parameters -->
<p class="mb-2 block text-sm dark:text-gray-100">How do you feel right now?</p>
<ul class="mb-4">
<li v-for="parameter in props.data.mood_tracking_parameters" :key="parameter.id" class="flex">
<input
:id="'input' + parameter.id"
v-model="form.parameter_id"
:value="parameter.id"
name="date-format"
type="radio"
class="relative mr-3 h-4 w-4 border-gray-300 text-sky-500 dark:border-gray-700" />
<label
:for="'input' + parameter.id"
class="block cursor-pointer font-medium text-gray-700 dark:text-gray-300">
<div class="mr-2 inline-block h-4 w-4 rounded-full" :class="parameter.hex_color" />
{{ parameter.label }}
</label>
</li>
</ul>
<div class="flex">
<span
v-if="!datePickerFieldShown"
class="mr-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 text-sm hover:bg-slate-300 dark:bg-slate-500 dark:text-white"
@click="showDatePickerField">
+ change date
</span>
<span
v-if="!noteFieldShown"
class="mr-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 text-sm hover:bg-slate-300 dark:bg-slate-500 dark:text-white"
@click="showNoteField">
+ note
</span>
<span
v-if="!hoursSleptFieldShown"
class="mr-2 flex cursor-pointer flex-wrap rounded-lg border bg-slate-200 px-1 py-1 text-sm hover:bg-slate-300 dark:bg-slate-500 dark:text-white"
@click="showHoursSleptField">
+ number of hours slept
</span>
</div>
<!-- date picker -->
<div v-if="datePickerFieldShown">
<p class="mt-2 mb-2 block text-sm dark:text-gray-100">Change date</p>
<v-date-picker v-model="form.date" :timezone="'UTC'" class="inline-block h-full" :model-config="modelConfig">
<template #default="{ inputValue, inputEvents }">
<input
class="rounded border bg-white px-2 py-1 dark:bg-gray-900"
:value="inputValue"
v-on="inputEvents" />
</template>
</v-date-picker>
</div>
<!-- note -->
<div v-if="noteFieldShown" class="mt-4">
<text-area v-model="form.note" :label="'Add a note'" :maxlength="65535" :textarea-class="'block w-full'" />
</div>
<!-- hours slept -->
<div v-if="hoursSleptFieldShown" class="mt-4">
<text-input
v-model="form.hours"
:label="'Number of hours slept'"
:autofocus="true"
:input-class="'block w-full'"
:type="'number'"
:min="0"
:max="24"
:required="false"
:autocomplete="false" />
</div>
</div>
<div class="flex justify-between p-5">
<pretty-span :text="$t('app.cancel')" :classes="'mr-3'" @click="createMoodEventModalShown = false" />
<pretty-button :text="$t('app.save')" :state="loadingState" :icon="'plus'" :classes="'save'" />
</div>
</form>
<!-- successShown -->
<div
v-if="successShown"
class="mb-4 flex items-center rounded-lg border border-gray-200 bg-white p-3 dark:border-gray-700 dark:bg-gray-900">
<img src="/img/dashboard_blank_how_are_you.svg" :alt="$t('Reminders')" class="mr-2 h-14 w-14" />
<div class="flex flex-col px-5">
<p class="mb-2"><span class="mr-1">🎉</span> Your mood has been recorded!</p>
<inertia-link :href="data.url.history" class="text-center text-blue-500 hover:underline"
>View history</inertia-link
>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.icon-sidebar {
color: #737e8d;
top: -2px;
}
.item-list {
&:hover:first-child {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
&:last-child {
border-bottom: 0;
}
&:hover:last-child {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
}
</style>
@@ -4,7 +4,7 @@
<span class="relative">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon-sidebar relative inline h-4 w-4 text-gray-300 hover:text-gray-600 dark:text-gray-400 dark:text-gray-700 dark:text-gray-300 hover:dark:text-gray-400"
class="icon-sidebar relative inline h-4 w-4 text-gray-300 hover:text-gray-600 dark:text-gray-400 hover:dark:text-gray-400"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor">
@@ -10,7 +10,34 @@ defineProps({
<template>
<Layout :layout-data="layoutData" :inside-vault="true">
<main class="relative sm:mt-24">
<!-- breadcrumb -->
<nav class="bg-white dark:bg-gray-900 sm:mt-20 sm:border-b">
<div class="max-w-8xl mx-auto hidden px-4 py-2 sm:px-6 md:block">
<div class="flex items-baseline justify-between space-x-6">
<ul class="text-sm">
<li class="mr-2 inline text-gray-600 dark:text-gray-400">
{{ $t('app.breadcrumb_location') }}
</li>
<li class="mr-2 inline">
<inertia-link :href="data.url.reports" class="text-blue-500 hover:underline">Reports</inertia-link>
</li>
<li class="relative mr-2 inline">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon-breadcrumb relative inline h-3 w-3"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</li>
<li class="inline">List of all important dates</li>
</ul>
</div>
</div>
</nav>
<main class="sm:mt-18 relative">
<div class="mx-auto max-w-3xl px-2 py-2 sm:py-6 sm:px-6 lg:px-8">
<!-- title -->
<div class="mb-5 items-center justify-between border-b border-gray-200 pb-2 dark:border-gray-700 sm:flex">
@@ -35,7 +62,7 @@ defineProps({
</div>
<!-- iteration over the month -->
<div v-for="month in data" :key="month.id" class="mb-6">
<div v-for="month in data.months" :key="month.id" class="mb-6">
<h2 class="font-bold">{{ month.month }}</h2>
<!-- important dates -->
@@ -0,0 +1,56 @@
<script setup>
import { Link } from '@inertiajs/inertia-vue3';
import Layout from '@/Shared/Layout.vue';
defineProps({
layoutData: Object,
data: Object,
});
</script>
<template>
<Layout :layout-data="layoutData" :inside-vault="true">
<main class="relative sm:mt-20">
<div class="mx-auto max-w-md px-2 py-2 sm:py-6 sm:px-6 lg:px-8">
<h2 class="mb-6 text-center text-lg">All the reports</h2>
<div class="mb-12 rounded-lg border border-gray-200 bg-white p-5 dark:border-gray-700 dark:bg-gray-900">
<ul>
<li class="mb-2 flex justify-start">
<Link :href="data.url.mood_tracking_events" class="text-blue-500 hover:underline">
Mood tracking events
</Link>
</li>
<li class="flex justify-start">
<Link :href="data.url.important_date_summary" class="text-blue-500 hover:underline">
Important date summary
</Link>
</li>
</ul>
</div>
</div>
</main>
</Layout>
</template>
<style lang="scss" scoped>
.icon-sidebar {
color: #737e8d;
top: -2px;
}
.item-list {
&:hover:first-child {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
&:last-child {
border-bottom: 0;
}
&:hover:last-child {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
}
</style>
@@ -0,0 +1,102 @@
<script setup>
import Layout from '@/Shared/Layout.vue';
defineProps({
layoutData: Object,
data: Object,
});
</script>
<template>
<Layout :layout-data="layoutData" :inside-vault="true">
<!-- breadcrumb -->
<nav class="bg-white dark:bg-gray-900 sm:mt-20 sm:border-b">
<div class="max-w-8xl mx-auto hidden px-4 py-2 sm:px-6 md:block">
<div class="flex items-baseline justify-between space-x-6">
<ul class="text-sm">
<li class="mr-2 inline text-gray-600 dark:text-gray-400">
{{ $t('app.breadcrumb_location') }}
</li>
<li class="mr-2 inline">
<inertia-link :href="data.url.reports" class="text-blue-500 hover:underline">Reports</inertia-link>
</li>
<li class="relative mr-2 inline">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon-breadcrumb relative inline h-3 w-3"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</li>
<li class="inline">List of all important dates</li>
</ul>
</div>
</div>
</nav>
<main class="sm:mt-18 relative">
<div class="mx-auto max-w-3xl px-2 py-2 sm:py-6 sm:px-6 lg:px-8">
<!-- title -->
<div class="mb-5 items-center justify-between border-b border-gray-200 pb-2 dark:border-gray-700 sm:flex">
<div class="mb-2 sm:mb-0">
<span class="relative">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="icon-sidebar relative inline h-4 w-4 text-gray-300 hover:text-gray-600 dark:text-gray-700 hover:dark:text-gray-400">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 8.25v-1.5m0 1.5c-1.355 0-2.697.056-4.024.166C6.845 8.51 6 9.473 6 10.608v2.513m6-4.87c1.355 0 2.697.055 4.024.165C17.155 8.51 18 9.473 18 10.608v2.513m-3-4.87v-1.5m-6 1.5v-1.5m12 9.75l-1.5.75a3.354 3.354 0 01-3 0 3.354 3.354 0 00-3 0 3.354 3.354 0 01-3 0 3.354 3.354 0 00-3 0 3.354 3.354 0 01-3 0L3 16.5m15-3.38a48.474 48.474 0 00-6-.37c-2.032 0-4.034.125-6 .37m12 0c.39.049.777.102 1.163.16 1.07.16 1.837 1.094 1.837 2.175v5.17c0 .62-.504 1.124-1.125 1.124H4.125A1.125 1.125 0 013 20.625v-5.17c0-1.08.768-2.014 1.837-2.174A47.78 47.78 0 016 13.12M12.265 3.11a.375.375 0 11-.53 0L12 2.845l.265.265zm-3 0a.375.375 0 11-.53 0L9 2.845l.265.265zm6 0a.375.375 0 11-.53 0L15 2.845l.265.265z" />
</svg>
</span>
Your mood this year
</div>
</div>
<!-- iteration over the month -->
<div class="flex justify-center">
<div v-for="month in data.months" :key="month.id" class="mb-6 flex flex-col text-center">
<h2 class="mr-2 mb-1 font-mono text-sm font-bold">{{ month.month_word }}</h2>
<div v-for="day in month.days" :key="day.id">
<div v-if="day.event" class="mr-2 inline-block h-4 w-4 rounded-full" :class="day.event.hex_color" />
<div v-else class="mr-2 inline-block h-4 w-4 rounded-full">
<div class="mr-2 inline-block h-4 w-4 rounded-full bg-slate-100" />
</div>
</div>
</div>
</div>
</div>
</main>
</Layout>
</template>
<style lang="scss" scoped>
.icon-sidebar {
color: #737e8d;
top: -2px;
}
.item-list {
&:hover:first-child {
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
&:last-child {
border-bottom: 0;
}
&:hover:last-child {
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
}
</style>
+11
View File
@@ -131,6 +131,15 @@
"
:data="feedItem.data"
:contact-view-mode="contactViewMode" />
<mood-tracking-event
v-if="
feedItem.action === 'mood_tracking_event_added' ||
feedItem.action === 'mood_tracking_event_updated' ||
feedItem.action === 'mood_tracking_event_deleted'
"
:data="feedItem.data"
:contact-view-mode="contactViewMode" />
</div>
<!-- details -->
@@ -175,6 +184,7 @@ import Addresses from '@/Shared/Modules/FeedItems/Address.vue';
import ContactInformation from '@/Shared/Modules/FeedItems/ContactInformation.vue';
import Pet from '@/Shared/Modules/FeedItems/Pet.vue';
import Goal from '@/Shared/Modules/FeedItems/Goal.vue';
import MoodTrackingEvent from '@/Shared/Modules/FeedItems/MoodTrackingEvent.vue';
export default {
components: {
@@ -186,6 +196,7 @@ export default {
ContactInformation,
Pet,
Goal,
MoodTrackingEvent,
},
props: {
@@ -0,0 +1,90 @@
<template>
<div class="rounded-lg border border-gray-300 dark:border-gray-700">
<!-- contact information -->
<div
v-if="!contactViewMode"
class="flex items-center border-b border-gray-300 px-3 py-2 text-sm dark:border-gray-700">
<avatar
:data="data.contact.avatar"
:classes="'rounded-full border-gray-200 dark:border-gray-800 border relative h-5 w-5 mr-2'" />
<div class="flex flex-col">
<inertia-link :href="data.contact.url" class="text-gray-800 hover:underline dark:text-gray-200">{{
data.contact.name
}}</inertia-link>
</div>
</div>
<div class="px-3 py-2">
<!-- the mood tracking event still exists in the system -->
<div v-if="data.mood_tracking_event.object">
<div class="mb-2 flex">
<div class="mr-2">
{{ data.mood_tracking_event.description }}
</div>
<!-- slept for -->
<div v-if="data.mood_tracking_event.object.number_of_hours_slept" class="flex items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="mr-1 h-4 w-4 text-gray-400">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z" />
</svg>
<span>{{ data.mood_tracking_event.object.number_of_hours_slept }} hours</span>
</div>
</div>
<!-- date -->
<div class="flex items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="mr-1 h-4 w-4 text-gray-400">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5" />
</svg>
{{ data.mood_tracking_event.object.rated_at }}
</div>
</div>
<!-- the mood tracking event was deleted -->
<span v-else class="mr-2 mb-2">
<span>{{ data.mood_tracking_event.description }}</span>
</span>
</div>
</div>
</template>
<script>
import Avatar from '@/Shared/Avatar.vue';
export default {
components: {
Avatar,
},
props: {
data: {
type: Object,
default: null,
},
contactViewMode: {
type: Boolean,
default: true,
},
},
};
</script>
+12 -1
View File
@@ -25,6 +25,7 @@ use App\Domains\Contact\ManageJobInformation\Web\Controllers\ContactModuleJobInf
use App\Domains\Contact\ManageLabels\Web\Controllers\ContactModuleLabelController;
use App\Domains\Contact\ManageLoans\Web\Controllers\ContactModuleLoanController;
use App\Domains\Contact\ManageLoans\Web\Controllers\ContactModuleToggleLoanController;
use App\Domains\Contact\ManageMoodTrackingEvents\Web\Controllers\ContactMoodTrackingEventsController;
use App\Domains\Contact\ManageNotes\Web\Controllers\ContactModuleNoteController;
use App\Domains\Contact\ManageNotes\Web\Controllers\ContactNotesController;
use App\Domains\Contact\ManagePets\Web\Controllers\ContactModulePetController;
@@ -95,6 +96,8 @@ use App\Domains\Vault\ManageJournals\Web\Controllers\PostTagController;
use App\Domains\Vault\ManageJournals\Web\Controllers\SliceOfLifeController;
use App\Domains\Vault\ManageJournals\Web\Controllers\SliceOfLifeCoverImageController;
use App\Domains\Vault\ManageReports\Web\Controllers\ReportImportantDateSummaryController;
use App\Domains\Vault\ManageReports\Web\Controllers\ReportIndexController;
use App\Domains\Vault\ManageReports\Web\Controllers\ReportMoodTrackingEventController;
use App\Domains\Vault\ManageTasks\Web\Controllers\VaultTaskController;
use App\Domains\Vault\ManageVault\Web\Controllers\VaultController;
use App\Domains\Vault\ManageVault\Web\Controllers\VaultFeedController;
@@ -178,7 +181,12 @@ Route::middleware([
// reports
Route::prefix('reports')->group(function () {
Route::get('', [ReportImportantDateSummaryController::class, 'index'])->name('vault.reports.index');
Route::get('', [ReportIndexController::class, 'index'])->name('vault.reports.index');
// mood tracking event
Route::get('moodTrackingEvents', [ReportMoodTrackingEventController::class, 'index'])->name('vault.reports.mood_tracking_events.index');
// important date summary
Route::get('importantDates', [ReportImportantDateSummaryController::class, 'index'])->name('vault.reports.important_dates.index');
});
@@ -313,6 +321,9 @@ Route::middleware([
// groups
Route::post('groups', [ContactModuleGroupController::class, 'store'])->name('contact.group.store');
Route::delete('groups/{group}', [ContactModuleGroupController::class, 'destroy'])->name('contact.group.destroy');
// mood tracking events
Route::post('moodTrackingEvents', [ContactMoodTrackingEventsController::class, 'store'])->name('contact.mood_tracking_event.store');
});
});
@@ -0,0 +1,62 @@
<?php
namespace Tests\Unit\Domains\Contact\ManageContactFeed\Web\ViewHelpers\Actions;
use App\Domains\Contact\ManageContactFeed\Web\ViewHelpers\Actions\ActionFeedMoodTrackingEvent;
use App\Models\Contact;
use App\Models\ContactFeedItem;
use App\Models\MoodTrackingEvent;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class ActionFeedMoodTrackingEventTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function it_gets_the_data_needed_for_the_view(): void
{
$user = $this->createAdministrator();
$contact = Contact::factory()->create([
'first_name' => 'John',
'last_name' => 'Doe',
]);
$moodTrackingEvent = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
'rated_at' => '2020-01-01 00:00:00',
'note' => 'Be awesome',
'number_of_hours_slept' => 3,
]);
$feedItem = ContactFeedItem::factory()->create([
'contact_id' => $contact->id,
'action' => ContactFeedItem::ACTION_MOOD_TRACKING_EVENT_CREATED,
'description' => 'Be awesome',
]);
$moodTrackingEvent->feedItem()->save($feedItem);
$array = ActionFeedMoodTrackingEvent::data($feedItem, $user);
$this->assertEquals(
[
'mood_tracking_event' => [
'object' => [
'id' => $moodTrackingEvent->id,
'rated_at' => 'Jan 01, 2020',
'note' => 'Be awesome',
'number_of_hours_slept' => 3,
],
'description' => 'Be awesome',
],
'contact' => [
'id' => $contact->id,
'name' => 'John Doe',
'age' => null,
'avatar' => $contact->avatar,
'url' => env('APP_URL').'/vaults/'.$contact->vault_id.'/contacts/'.$contact->id,
],
],
$array
);
}
}
@@ -0,0 +1,131 @@
<?php
namespace Tests\Unit\Domains\Contact\ManageMoodTrackingEvents\Services;
use App\Domains\Contact\ManageMoodTrackingEvents\Services\CreateMoodTrackingEvent;
use App\Exceptions\NotEnoughPermissionException;
use App\Models\Account;
use App\Models\Contact;
use App\Models\ContactFeedItem;
use App\Models\MoodTrackingParameter;
use App\Models\User;
use App\Models\Vault;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Validation\ValidationException;
use Tests\TestCase;
class CreateMoodTrackingEventTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function it_creates_a_mood_tracking_event(): void
{
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingParameter = MoodTrackingParameter::factory()->create(['vault_id' => $vault->id]);
$this->executeService($regis, $regis->account, $vault, $contact, $moodTrackingParameter);
}
/** @test */
public function it_fails_if_wrong_parameters_are_given(): void
{
$request = [
'title' => 'Ross',
];
$this->expectException(ValidationException::class);
(new CreateMoodTrackingEvent())->execute($request);
}
/** @test */
public function it_fails_if_user_doesnt_belong_to_account(): void
{
$this->expectException(ModelNotFoundException::class);
$regis = $this->createUser();
$account = Account::factory()->create();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingParameter = MoodTrackingParameter::factory()->create(['vault_id' => $vault->id]);
$this->executeService($regis, $account, $vault, $contact, $moodTrackingParameter);
}
/** @test */
public function it_fails_if_contact_doesnt_belong_to_vault(): void
{
$this->expectException(ModelNotFoundException::class);
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create();
$moodTrackingParameter = MoodTrackingParameter::factory()->create(['vault_id' => $vault->id]);
$this->executeService($regis, $regis->account, $vault, $contact, $moodTrackingParameter);
}
/** @test */
public function it_fails_if_user_doesnt_have_right_permission_in_vault(): void
{
$this->expectException(NotEnoughPermissionException::class);
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_VIEW, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingParameter = MoodTrackingParameter::factory()->create(['vault_id' => $vault->id]);
$this->executeService($regis, $regis->account, $vault, $contact, $moodTrackingParameter);
}
/** @test */
public function it_fails_if_parameter_doesnt_belong_to_vault(): void
{
$this->expectException(ModelNotFoundException::class);
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingParameter = MoodTrackingParameter::factory()->create();
$this->executeService($regis, $regis->account, $vault, $contact, $moodTrackingParameter);
}
private function executeService(User $author, Account $account, Vault $vault, Contact $contact, MoodTrackingParameter $moodTrackingParameter): void
{
$request = [
'account_id' => $account->id,
'vault_id' => $vault->id,
'author_id' => $author->id,
'contact_id' => $contact->id,
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
'rated_at' => '1982-02-03',
'note' => 'fou',
'number_of_hours_slept' => 3,
];
$event = (new CreateMoodTrackingEvent())->execute($request);
$this->assertDatabaseHas('mood_tracking_events', [
'id' => $event->id,
'contact_id' => $contact->id,
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
'rated_at' => '1982-02-03 00:00:00',
'note' => 'fou',
'number_of_hours_slept' => 3,
]);
$this->assertDatabaseHas('contact_feed_items', [
'contact_id' => $contact->id,
'action' => ContactFeedItem::ACTION_MOOD_TRACKING_EVENT_CREATED,
]);
}
}
@@ -0,0 +1,131 @@
<?php
namespace Tests\Unit\Domains\Contact\ManageMoodTrackingEvents\Services;
use App\Domains\Contact\ManageMoodTrackingEvents\Services\DestroyMoodTrackingEvent;
use App\Exceptions\NotEnoughPermissionException;
use App\Models\Account;
use App\Models\Contact;
use App\Models\ContactFeedItem;
use App\Models\MoodTrackingEvent;
use App\Models\User;
use App\Models\Vault;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Validation\ValidationException;
use Tests\TestCase;
class DestroyMoodTrackingEventTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function it_destroys_a_mood_tracking_event(): void
{
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingEvent = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
]);
$this->executeService($regis, $regis->account, $vault, $contact, $moodTrackingEvent);
}
/** @test */
public function it_fails_if_wrong_parameters_are_given(): void
{
$request = [
'title' => 'Ross',
];
$this->expectException(ValidationException::class);
(new DestroyMoodTrackingEvent())->execute($request);
}
/** @test */
public function it_fails_if_user_doesnt_belong_to_account(): void
{
$this->expectException(ModelNotFoundException::class);
$regis = $this->createUser();
$account = Account::factory()->create();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingEvent = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
]);
$this->executeService($regis, $account, $vault, $contact, $moodTrackingEvent);
}
/** @test */
public function it_fails_if_contact_doesnt_belong_to_vault(): void
{
$this->expectException(ModelNotFoundException::class);
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create();
$moodTrackingEvent = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
]);
$this->executeService($regis, $regis->account, $vault, $contact, $moodTrackingEvent);
}
/** @test */
public function it_fails_if_user_doesnt_have_right_permission_in_initial_vault(): void
{
$this->expectException(NotEnoughPermissionException::class);
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_VIEW, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingEvent = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
]);
$this->executeService($regis, $regis->account, $vault, $contact, $moodTrackingEvent);
}
/** @test */
public function it_fails_if_event_does_not_exist(): void
{
$this->expectException(ModelNotFoundException::class);
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingEvent = MoodTrackingEvent::factory()->create();
$this->executeService($regis, $regis->account, $vault, $contact, $moodTrackingEvent);
}
private function executeService(User $author, Account $account, Vault $vault, Contact $contact, MoodTrackingEvent $moodTrackingEvent): void
{
$request = [
'account_id' => $account->id,
'vault_id' => $vault->id,
'author_id' => $author->id,
'contact_id' => $contact->id,
'mood_tracking_event_id' => $moodTrackingEvent->id,
];
(new DestroyMoodTrackingEvent())->execute($request);
$this->assertDatabaseMissing('mood_tracking_events', [
'id' => $moodTrackingEvent->id,
]);
$this->assertDatabaseHas('contact_feed_items', [
'contact_id' => $contact->id,
'action' => ContactFeedItem::ACTION_MOOD_TRACKING_EVENT_DESTROYED,
]);
}
}
@@ -0,0 +1,172 @@
<?php
namespace Tests\Unit\Domains\Contact\ManageMoodTrackingEvents\Services;
use App\Domains\Contact\ManageMoodTrackingEvents\Services\UpdateMoodTrackingEvent;
use App\Exceptions\NotEnoughPermissionException;
use App\Models\Account;
use App\Models\Contact;
use App\Models\ContactFeedItem;
use App\Models\ContactInformationType;
use App\Models\MoodTrackingEvent;
use App\Models\MoodTrackingParameter;
use App\Models\User;
use App\Models\Vault;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Validation\ValidationException;
use Tests\TestCase;
class UpdateMoodTrackingEventTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function it_updates_a_mood_tracking_event(): void
{
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingParameter = MoodTrackingParameter::factory()->create(['vault_id' => $vault->id]);
$event = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
]);
$this->executeService($regis, $regis->account, $vault, $contact, $event, $moodTrackingParameter);
}
/** @test */
public function it_fails_if_wrong_parameters_are_given(): void
{
$request = [
'title' => 'Ross',
];
$this->expectException(ValidationException::class);
(new UpdateMoodTrackingEvent())->execute($request);
}
/** @test */
public function it_fails_if_user_doesnt_belong_to_account(): void
{
$this->expectException(ModelNotFoundException::class);
$regis = $this->createUser();
$account = Account::factory()->create();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingParameter = MoodTrackingParameter::factory()->create(['vault_id' => $vault->id]);
$event = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
]);
$this->executeService($regis, $account, $vault, $contact, $event, $moodTrackingParameter);
}
/** @test */
public function it_fails_if_contact_doesnt_belong_to_vault(): void
{
$this->expectException(ModelNotFoundException::class);
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create();
$moodTrackingParameter = MoodTrackingParameter::factory()->create(['vault_id' => $vault->id]);
$event = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
]);
$this->executeService($regis, $regis->account, $vault, $contact, $event, $moodTrackingParameter);
}
/** @test */
public function it_fails_if_user_doesnt_have_right_permission_in_initial_vault(): void
{
$this->expectException(NotEnoughPermissionException::class);
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_VIEW, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingParameter = MoodTrackingParameter::factory()->create(['vault_id' => $vault->id]);
$event = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
]);
$this->executeService($regis, $regis->account, $vault, $contact, $event, $moodTrackingParameter);
}
/** @test */
public function it_fails_if_event_is_not_in_the_contact(): void
{
$this->expectException(ModelNotFoundException::class);
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$event = ContactInformationType::factory()->create();
$moodTrackingParameter = MoodTrackingParameter::factory()->create(['vault_id' => $vault->id]);
$event = MoodTrackingEvent::factory()->create([
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
]);
$this->executeService($regis, $regis->account, $vault, $contact, $event, $moodTrackingParameter);
}
/** @test */
public function it_fails_if_parameter_doesnt_belong_to_vault(): void
{
$this->expectException(ModelNotFoundException::class);
$regis = $this->createUser();
$vault = $this->createVault($regis->account);
$vault = $this->setPermissionInVault($regis, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingParameter = MoodTrackingParameter::factory()->create();
$event = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
]);
$this->executeService($regis, $regis->account, $vault, $contact, $event, $moodTrackingParameter);
}
private function executeService(User $author, Account $account, Vault $vault, Contact $contact, MoodTrackingEvent $event, MoodTrackingParameter $moodTrackingParameter): void
{
$request = [
'account_id' => $account->id,
'vault_id' => $vault->id,
'author_id' => $author->id,
'contact_id' => $contact->id,
'mood_tracking_event_id' => $event->id,
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
'rated_at' => '1982-02-03',
'note' => 'fou',
'number_of_hours_slept' => 3,
];
$event = (new UpdateMoodTrackingEvent())->execute($request);
$this->assertDatabaseHas('mood_tracking_events', [
'id' => $event->id,
'contact_id' => $contact->id,
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
'rated_at' => '1982-02-03 00:00:00',
'note' => 'fou',
'number_of_hours_slept' => 3,
]);
$this->assertDatabaseHas('contact_feed_items', [
'contact_id' => $contact->id,
'action' => ContactFeedItem::ACTION_MOOD_TRACKING_EVENT_UPDATED,
]);
}
}
@@ -34,31 +34,37 @@ class ReportImportantDateSummaryIndexViewHelperTest extends TestCase
'label' => 'stop it',
]);
$collection = ReportImportantDateSummaryIndexViewHelper::data($vault, $user);
$array = ReportImportantDateSummaryIndexViewHelper::data($vault, $user);
$this->assertEquals(
0,
$collection->toArray()[0]['id']
$array['months']->toArray()[0]['id']
);
$this->assertEquals(
'Oct 2022',
$collection->toArray()[0]['month']
$array['months']->toArray()[0]['month']
);
$this->assertEquals(
[],
$collection->toArray()[0]['important_dates']->toArray()
$array['months']->toArray()[0]['important_dates']->toArray()
);
$this->assertEquals(
$importantDate->id,
$collection->toArray()[5]['important_dates']->toArray()[0]['id']
$array['months']->toArray()[5]['important_dates']->toArray()[0]['id']
);
$this->assertEquals(
'stop it',
$collection->toArray()[5]['important_dates']->toArray()[0]['label']
$array['months']->toArray()[5]['important_dates']->toArray()[0]['label']
);
$this->assertEquals(
'Mar 12, 2024',
$collection->toArray()[5]['important_dates']->toArray()[0]['happened_at']
$array['months']->toArray()[5]['important_dates']->toArray()[0]['happened_at']
);
$this->assertEquals(
[
'reports' => env('APP_URL').'/vaults/'.$vault->id.'/reports',
],
$array['url']
);
}
}
@@ -0,0 +1,30 @@
<?php
namespace Tests\Unit\Domains\Vault\ManageReports\Web\ViewHelpers;
use App\Domains\Vault\ManageReports\Web\ViewHelpers\ReportIndexViewHelper;
use App\Models\Vault;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class ReportIndexViewHelperTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function it_gets_the_data_needed_for_the_view(): void
{
$vault = Vault::factory()->create();
$array = ReportIndexViewHelper::data($vault);
$this->assertEquals(
[
'url' => [
'mood_tracking_events' => env('APP_URL').'/vaults/'.$vault->id.'/reports/moodTrackingEvents',
'important_date_summary' => env('APP_URL').'/vaults/'.$vault->id.'/reports/importantDates',
],
],
$array
);
}
}
@@ -0,0 +1,46 @@
<?php
namespace Tests\Unit\Domains\Vault\ManageReports\Web\ViewHelpers;
use App\Domains\Vault\ManageReports\Web\ViewHelpers\ReportMoodTrackingEventIndexViewHelper;
use App\Models\Contact;
use App\Models\MoodTrackingEvent;
use App\Models\MoodTrackingParameter;
use App\Models\Vault;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class ReportMoodTrackingEventIndexViewHelperTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function it_gets_the_data_needed_for_the_view(): void
{
Carbon::setTestNow(Carbon::create(2018, 10, 10));
$user = $this->createUser();
$vault = $this->createVault($user->account);
$vault = $this->setPermissionInVault($user, Vault::PERMISSION_EDIT, $vault);
$contact = Contact::factory()->create(['vault_id' => $vault->id]);
$moodTrackingParameter = MoodTrackingParameter::factory()->create([
'vault_id' => $vault->id,
]);
$moodTrackingEvent = MoodTrackingEvent::factory()->create([
'contact_id' => $contact->id,
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
'rated_at' => '2018-01-01 00:00:00',
]);
$array = ReportMoodTrackingEventIndexViewHelper::data($vault, $user, 2018);
$this->assertEquals(
1,
$array['months']->toArray()[0]['id']
);
$this->assertEquals(
'Jan',
$array['months']->toArray()[0]['month_word']
);
}
}
@@ -6,6 +6,8 @@ use App\Domains\Vault\ManageVault\Web\ViewHelpers\VaultShowViewHelper;
use App\Models\Contact;
use App\Models\ContactReminder;
use App\Models\ContactTask;
use App\Models\MoodTrackingEvent;
use App\Models\MoodTrackingParameter;
use App\Models\User;
use App\Models\UserNotificationChannel;
use App\Models\Vault;
@@ -245,4 +247,67 @@ class VaultShowViewHelperTest extends TestCase
$array['tasks']->toArray()
);
}
/** @test */
public function it_gets_the_mood_tracking_parameters(): void
{
$ross = $this->createAdministrator();
$vault = $this->createVault($ross->account);
$vault = $this->setPermissionInVault($ross, Vault::PERMISSION_MANAGE, $vault);
$moodTrackingParameter = MoodTrackingParameter::factory()->create([
'vault_id' => $vault->id,
]);
$contact = $ross->getContactInVault($vault);
Carbon::setTestNow(Carbon::create(2018, 1, 1));
$array = VaultShowViewHelper::moodTrackingEvents($vault, $ross);
$this->assertEquals(
[
0 => [
'id' => $moodTrackingParameter->id,
'label' => $moodTrackingParameter->label,
'hex_color' => $moodTrackingParameter->hex_color,
],
],
$array['mood_tracking_parameters']->toArray()
);
$this->assertEquals(
'2018-01-01',
$array['current_date']
);
$this->assertEquals(
[
'history' => env('APP_URL').'/vaults/'.$vault->id.'/reports/moodTrackingEvents',
'store' => env('APP_URL').'/vaults/'.$vault->id.'/contacts/'.$contact->id.'/moodTrackingEvents',
],
$array['url']
);
}
/** @test */
public function it_gets_the_dto_for_mood_tracking_event(): void
{
$user = User::factory()->create();
$moodTrackingParameter = MoodTrackingParameter::factory()->create();
$moodTrackingEvent = MoodTrackingEvent::factory()->create([
'mood_tracking_parameter_id' => $moodTrackingParameter->id,
'rated_at' => '2018-01-01 00:00:00',
'note' => 'note',
'number_of_hours_slept' => 8,
]);
$array = VaultShowViewHelper::dtoMoodTrackingEvent($moodTrackingEvent, $user);
$this->assertEquals(
[
'id' => $moodTrackingEvent->id,
'label' => $moodTrackingEvent->moodTrackingParameter->label,
'rated_at' => 'Jan 01, 2018',
'note' => 'note',
'number_of_hours_slept' => 8,
],
$array
);
}
}
@@ -19,7 +19,6 @@ class UpdateMoodTrackingParameterPositionTest extends TestCase
/** @test */
public function it_updates_a_mood_tracking_parameter_position(): void
{
$ross = $this->createAdministrator();
$ross = $this->createAdministrator();
$vault = $this->createVault($ross->account);
$vault = $this->setPermissionInVault($ross, Vault::PERMISSION_MANAGE, $vault);
+11
View File
@@ -125,6 +125,17 @@ class DateHelperTest extends TestCase
);
}
/** @test */
public function it_gets_a_short_month(): void
{
$date = Carbon::createFromFormat('Y-m-d H:i:s', '1978-10-01 17:56:03');
$this->assertEquals(
'Oct',
DateHelper::formatMonthNumber($date)
);
}
/** @test */
public function it_gets_a_short_month_and_year(): void
{
+12
View File
@@ -18,6 +18,7 @@ use App\Models\Group;
use App\Models\Label;
use App\Models\LifeEvent;
use App\Models\Loan;
use App\Models\MoodTrackingEvent;
use App\Models\Note;
use App\Models\Pet;
use App\Models\Post;
@@ -282,6 +283,17 @@ class ContactTest extends TestCase
$this->assertTrue($contact->lifeEvents()->exists());
}
/** @test */
public function it_has_many_mood_tracking_events(): void
{
$contact = Contact::factory()->create();
MoodTrackingEvent::factory()->count(2)->create([
'contact_id' => $contact->id,
]);
$this->assertTrue($contact->moodTrackingEvents()->exists());
}
/** @test */
public function it_has_many_addresses(): void
{
@@ -0,0 +1,28 @@
<?php
namespace Tests\Unit\Models;
use App\Models\MoodTrackingEvent;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class MoodTrackingEventTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function it_has_one_contact()
{
$event = MoodTrackingEvent::factory()->create();
$this->assertTrue($event->contact()->exists());
}
/** @test */
public function it_has_one_parameter()
{
$event = MoodTrackingEvent::factory()->create();
$this->assertTrue($event->moodTrackingParameter()->exists());
}
}
@@ -2,6 +2,7 @@
namespace Tests\Unit\Models;
use App\Models\MoodTrackingEvent;
use App\Models\MoodTrackingParameter;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
@@ -32,6 +33,17 @@ class MoodTrackingParameterTest extends TestCase
);
}
/** @test */
public function it_has_many_events(): void
{
$parameter = MoodTrackingParameter::factory()->create();
MoodTrackingEvent::factory()->count(2)->create([
'mood_tracking_parameter_id' => $parameter->id,
]);
$this->assertTrue($parameter->moodTrackingEvents()->exists());
}
/** @test */
public function it_gets_the_custom_label_if_defined()
{