feat: add distance to life events (monicahq/chandler#431)

This commit is contained in:
Mazarin
2023-03-05 11:16:27 -05:00
committed by GitHub
parent a4b57f8d78
commit 38d2c7c95b
28 changed files with 558 additions and 30 deletions
@@ -39,7 +39,8 @@ class CreateLifeEvent extends BaseService implements ServiceInterface
'currency_id' => 'nullable|integer|exists:currencies,id',
'paid_by_contact_id' => 'nullable|integer|exists:contacts,id',
'duration_in_minutes' => 'nullable|integer',
'distance_in_km' => 'nullable|integer',
'distance' => 'nullable|integer',
'distance_unit' => 'nullable|string|max:255',
'from_place' => 'nullable|string|max:255',
'to_place' => 'nullable|string|max:255',
'place' => 'nullable|string|max:255',
@@ -129,7 +130,8 @@ class CreateLifeEvent extends BaseService implements ServiceInterface
'currency_id' => $this->valueOrNull($this->data, 'currency_id'),
'paid_by_contact_id' => $this->valueOrNull($this->data, 'paid_by_contact_id'),
'duration_in_minutes' => $this->valueOrNull($this->data, 'duration_in_minutes'),
'distance_in_km' => $this->valueOrNull($this->data, 'distance_in_km'),
'distance' => $this->valueOrNull($this->data, 'distance'),
'distance_unit' => $this->valueOrNull($this->data, 'distance_unit'),
'from_place' => $this->valueOrNull($this->data, 'from_place'),
'to_place' => $this->valueOrNull($this->data, 'to_place'),
'place' => $this->valueOrNull($this->data, 'place'),
@@ -40,7 +40,8 @@ class UpdateLifeEvent extends BaseService implements ServiceInterface
'currency_id' => 'nullable|integer|exists:currencies,id',
'paid_by_contact_id' => 'nullable|integer|exists:contacts,id',
'duration_in_minutes' => 'nullable|integer',
'distance_in_km' => 'nullable|integer',
'distance' => 'nullable|integer',
'distance_unit' => 'nullable|string|max:255',
'from_place' => 'nullable|string|max:255',
'to_place' => 'nullable|string|max:255',
'place' => 'nullable|string|max:255',
@@ -114,7 +115,8 @@ class UpdateLifeEvent extends BaseService implements ServiceInterface
$this->lifeEvent->currency_id = $this->valueOrNull($this->data, 'currency_id');
$this->lifeEvent->paid_by_contact_id = $this->valueOrNull($this->data, 'paid_by_contact_id');
$this->lifeEvent->duration_in_minutes = $this->valueOrNull($this->data, 'duration_in_minutes');
$this->lifeEvent->distance_in_km = $this->valueOrNull($this->data, 'distance_in_km');
$this->lifeEvent->distance = $this->valueOrNull($this->data, 'distance');
$this->lifeEvent->distance_unit = $this->valueOrNull($this->data, 'distance_unit');
$this->lifeEvent->from_place = $this->valueOrNull($this->data, 'from_place');
$this->lifeEvent->to_place = $this->valueOrNull($this->data, 'to_place');
$this->lifeEvent->place = $this->valueOrNull($this->data, 'place');
@@ -40,7 +40,8 @@ class ContactModuleLifeEventController extends Controller
'currency_id' => $request->input('currency_id'),
'paid_by_contact_id' => $request->input('paid_by_contact_id'),
'duration_in_minutes' => $request->input('duration_in_minutes'),
'distance_in_km' => $request->input('distance_in_km'),
'distance' => $request->input('distance'),
'distance_unit' => $request->input('distance_unit'),
'from_place' => $request->input('from_place'),
'to_place' => $request->input('to_place'),
'place' => $request->input('place'),
@@ -67,7 +67,8 @@ class ContactModuleTimelineEventController extends Controller
'currency_id' => $request->input('currency_id'),
'paid_by_contact_id' => $request->input('paid_by_contact_id'),
'duration_in_minutes' => $request->input('duration_in_minutes'),
'distance_in_km' => $request->input('distance_in_km'),
'distance' => $request->input('distance'),
'distance_unit' => $request->input('distance_unit'),
'from_place' => $request->input('from_place'),
'to_place' => $request->input('to_place'),
'place' => $request->input('place'),
@@ -4,6 +4,7 @@ namespace App\Domains\Contact\ManageLifeEvents\Web\ViewHelpers;
use App\Helpers\ContactCardHelper;
use App\Helpers\DateHelper;
use App\Helpers\DistanceHelper;
use App\Models\Contact;
use App\Models\LifeEvent;
use App\Models\LifeEventCategory;
@@ -113,7 +114,8 @@ class ModuleLifeEventViewHelper
'currency_id' => $lifeEvent->currency_id,
'paid_by_contact_id' => $lifeEvent->paid_by_contact_id,
'duration_in_minutes' => $lifeEvent->duration_in_minutes,
'distance_in_km' => $lifeEvent->distance_in_km,
'distance' => $lifeEvent->distance && $lifeEvent->distance_unit ? DistanceHelper::format($user, $lifeEvent->distance, $lifeEvent->distance_unit) : null,
'distance_unit' => $lifeEvent->distance_unit,
'from_place' => $lifeEvent->from_place,
'to_place' => $lifeEvent->to_place,
'place' => $lifeEvent->place,
@@ -0,0 +1,53 @@
<?php
namespace App\Domains\Settings\ManageUserPreferences\Services;
use App\Interfaces\ServiceInterface;
use App\Models\User;
use App\Services\BaseService;
class StoreDistanceFormatPreference extends BaseService implements ServiceInterface
{
private array $data;
/**
* Get the validation rules that apply to the service.
*/
public function rules(): array
{
return [
'account_id' => 'required|integer|exists:accounts,id',
'author_id' => 'required|integer|exists:users,id',
'distance_format' => 'required|string|max:255',
];
}
/**
* Get the permissions that apply to the user calling the service.
*/
public function permissions(): array
{
return [
'author_must_belong_to_account',
];
}
/**
* Store distance format preferences for the given user.
*/
public function execute(array $data): User
{
$this->data = $data;
$this->validateRules($data);
$this->updateUser();
return $this->author;
}
private function updateUser(): void
{
$this->author->distance_format = $this->data['distance_format'];
$this->author->save();
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Domains\Settings\ManageUserPreferences\Web\Controllers;
use App\Domains\Settings\ManageUserPreferences\Services\StoreDistanceFormatPreference;
use App\Domains\Settings\ManageUserPreferences\Web\ViewHelpers\UserPreferencesIndexViewHelper;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class PreferencesDistanceFormatController extends Controller
{
public function store(Request $request)
{
$data = [
'account_id' => Auth::user()->account_id,
'author_id' => Auth::id(),
'distance_format' => $request->input('distanceFormat'),
];
$user = (new StoreDistanceFormatPreference())->execute($data);
return response()->json([
'data' => UserPreferencesIndexViewHelper::dtoDistanceFormat($user),
], 200);
}
}
@@ -17,6 +17,7 @@ class UserPreferencesIndexViewHelper
'date_format' => self::dtoDateFormat($user),
'timezone' => self::dtoTimezone($user),
'number_format' => self::dtoNumberFormat($user),
'distance_format' => self::dtoDistanceFormat($user),
'maps' => self::dtoMapsPreferences($user),
'locale' => self::dtoLocale($user),
'url' => [
@@ -131,6 +132,16 @@ class UserPreferencesIndexViewHelper
];
}
public static function dtoDistanceFormat(User $user): array
{
return [
'number_format' => $user->distance_format,
'url' => [
'store' => route('settings.preferences.distance.store'),
],
];
}
public static function dtoMapsPreferences(User $user): array
{
$collection = collect();
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App\Helpers;
use App\Models\User;
class DistanceHelper
{
/**
* Format the distance according to the preferences of the user.
*/
public static function format(User $user, int $distance, string $unit): string
{
if ($user->distance_format === User::DISTANCE_UNIT_KM && $unit === User::DISTANCE_UNIT_MILES) {
$distance = round($distance * 1.609344, 2);
} elseif ($user->distance_format === User::DISTANCE_UNIT_MILES && $unit === User::DISTANCE_UNIT_KM) {
$distance = round($distance / 1.609344, 2);
}
return trans('app.distance_format_'.$user->distance_format, ['distance' => $distance]);
}
}
+2 -1
View File
@@ -30,7 +30,8 @@ class LifeEvent extends Model
'currency_id',
'paid_by_contact_id',
'duration_in_minutes',
'distance_in_km',
'distance',
'distance_unit',
'from_place',
'to_place',
'place',
+8
View File
@@ -40,6 +40,13 @@ class User extends Authenticatable implements MustVerifyEmail, HasLocalePreferen
public const MAPS_SITE_OPEN_STREET_MAPS = 'open_street_maps';
/**
* Possible distance unit.
*/
public const DISTANCE_UNIT_MILES = 'mi';
public const DISTANCE_UNIT_KM = 'km';
/**
* The attributes that are mass assignable.
*
@@ -58,6 +65,7 @@ class User extends Authenticatable implements MustVerifyEmail, HasLocalePreferen
'name_order',
'date_format',
'number_format',
'distance_format',
'timezone',
'default_map_site',
'locale',
+1 -1
View File
@@ -32,7 +32,7 @@ class LifeEventFactory extends Factory
'currency_id' => null,
'paid_by_contact_id' => Contact::factory(),
'duration_in_minutes' => $this->faker->randomNumber(),
'distance_in_km' => $this->faker->randomNumber(),
'distance' => $this->faker->randomNumber(),
'from_place' => $this->faker->city(),
'to_place' => $this->faker->city(),
'place' => $this->faker->city(),
@@ -25,6 +25,7 @@ return new class() extends Migration
$table->string('timezone')->nullable();
$table->string('number_format')->default(User::NUMBER_FORMAT_TYPE_COMMA_THOUSANDS_DOT_DECIMAL);
$table->string('default_map_site')->default(User::MAPS_SITE_OPEN_STREET_MAPS);
$table->string('distance_format')->default(User::DISTANCE_UNIT_MILES);
$table->string('password')->nullable();
$table->boolean('is_account_administrator')->default(false);
$table->boolean('help_shown')->default(true);
@@ -74,7 +74,8 @@ return new class() extends Migration
$table->unsignedBigInteger('currency_id')->nullable();
$table->unsignedBigInteger('paid_by_contact_id')->nullable();
$table->integer('duration_in_minutes')->nullable();
$table->integer('distance_in_km')->nullable();
$table->integer('distance')->nullable();
$table->char('distance_unit', 2)->nullable();
$table->string('from_place')->nullable();
$table->string('to_place')->nullable();
$table->string('place')->nullable();
+3
View File
@@ -133,4 +133,7 @@ return [
'min_read' => '{count} min read',
'word_count' => '{count} words',
'distance_format_km' => ':distance km',
'distance_format_mi' => ':distance miles',
];
+5
View File
@@ -39,6 +39,11 @@ return [
'user_preferences_number_format_title' => 'How should we display numerical values',
'user_preferences_number_format_description' => 'Current way of displaying numbers:',
'user_preferences_distance_format_title' => 'How should we display distance values',
'user_preferences_distance_format_description' => 'Current way of displaying distances:',
'user_preferences_distance_format_km' => 'kilometers (km)',
'user_preferences_distance_format_miles' => 'miles (mi)',
'user_preferences_timezone_title' => 'Timezone',
'user_preferences_timezone_description' => 'Regardless of where you are located in the world, have dates displayed in your own timezone.',
'user_preferences_timezone_current' => 'Current timezone:',
@@ -43,6 +43,8 @@
<number-format :data="data.number_format" />
<distance-format :data="data.distance_format" />
<timezone :data="data.timezone" />
<maps :data="data.maps" />
@@ -56,6 +58,7 @@ import Layout from '@/Shared/Layout.vue';
import NameOrder from '@/Pages/Settings/Preferences/Partials/NameOrder.vue';
import DateFormat from '@/Pages/Settings/Preferences/Partials/DateFormat.vue';
import NumberFormat from '@/Pages/Settings/Preferences/Partials/NumberFormat.vue';
import DistanceFormat from '@/Pages/Settings/Preferences/Partials/DistanceFormat.vue';
import Timezone from '@/Pages/Settings/Preferences/Partials/Timezone.vue';
import Maps from '@/Pages/Settings/Preferences/Partials/Maps.vue';
import Locale from '@/Pages/Settings/Preferences/Partials/Locale.vue';
@@ -68,6 +71,7 @@ export default {
DateFormat,
Timezone,
NumberFormat,
DistanceFormat,
Maps,
Locale,
HelpPreference,
@@ -0,0 +1,141 @@
<template>
<div class="mb-16">
<!-- title + cta -->
<div class="mb-3 mt-8 items-center justify-between sm:mt-0 sm:flex">
<h3 class="mb-4 flex font-semibold sm:mb-0">
<span class="mr-1"> </span>
<span class="mr-2">
{{ $t('settings.user_preferences_distance_format_title') }}
</span>
<help :url="$page.props.help_links.settings_preferences_numerical_format" :top="'5px'" />
</h3>
<pretty-button v-if="!editMode" :text="$t('app.edit')" @click="enableEditMode" />
</div>
<!-- normal mode -->
<div v-if="!editMode" class="mb-6 rounded-lg border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">
<p class="px-5 py-2">
<span class="mb-2 block">{{ $t('settings.user_preferences_number_format_description') }}</span>
<span class="mb-2 block rounded bg-slate-100 px-5 py-2 text-sm dark:bg-slate-900">{{
localDistanceFormat
}}</span>
</p>
</div>
<!-- edit mode -->
<form
v-if="editMode"
class="bg-form mb-6 rounded-lg border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900"
@submit.prevent="submit()">
<div class="border-b border-gray-200 px-5 py-2 dark:border-gray-700">
<errors :errors="form.errors" />
<div class="mt-2 mb-2 flex items-center">
<input
id="km"
v-model="form.distanceFormat"
value="km"
name="date-format"
type="radio"
class="h-4 w-4 border-gray-300 text-sky-500 dark:border-gray-700" />
<label for="km" class="ml-3 block cursor-pointer text-sm font-medium text-gray-700 dark:text-gray-300">
{{ $t('settings.user_preferences_distance_format_km') }}
</label>
</div>
<div class="mb-2 flex items-center">
<input
id="miles"
v-model="form.distanceFormat"
value="miles"
name="date-format"
type="radio"
class="h-4 w-4 border-gray-300 text-sky-500 dark:border-gray-700" />
<label for="miles" class="ml-3 block cursor-pointer text-sm font-medium text-gray-700 dark:text-gray-300">
{{ $t('settings.user_preferences_distance_format_miles') }}
</label>
</div>
</div>
<!-- actions -->
<div class="flex justify-between p-5">
<pretty-link :text="$t('app.cancel')" :classes="'mr-3'" @click="editMode = false" />
<pretty-button :text="$t('app.save')" :state="loadingState" :icon="'check'" :classes="'save'" />
</div>
</form>
</div>
</template>
<script>
import PrettyButton from '@/Shared/Form/PrettyButton.vue';
import PrettyLink from '@/Shared/Form/PrettyLink.vue';
import Errors from '@/Shared/Form/Errors.vue';
import Help from '@/Shared/Help.vue';
export default {
components: {
PrettyButton,
PrettyLink,
Errors,
Help,
},
props: {
data: {
type: Object,
default: null,
},
},
data() {
return {
loadingState: '',
editMode: false,
localDistanceFormat: '',
form: {
distanceFormat: '',
errors: [],
},
};
},
mounted() {
this.localDistanceFormat = this.data.number_format;
this.form.distanceFormat = this.data.number_format;
},
methods: {
enableEditMode() {
this.editMode = true;
},
submit() {
this.loadingState = 'loading';
axios
.post(this.data.url.store, this.form)
.then(() => {
this.localDistanceFormat = this.form.distanceFormat;
this.editMode = false;
this.loadingState = null;
})
.catch((error) => {
this.loadingState = null;
this.form.errors = error.response.data;
});
},
},
};
</script>
<style lang="scss" scoped>
pre {
background-color: #1f2937;
color: #c9ef78;
}
.example {
border-bottom-left-radius: 9px;
border-bottom-right-radius: 9px;
}
</style>
+9 -1
View File
@@ -130,7 +130,7 @@ defineProps({
<!-- right -->
<div class="p-3 sm:p-0">
<!-- cta -->
<div class="mb-6 flex justify-center">
<div class="mb-8 flex justify-center">
<pretty-link
v-if="layoutData.vault.permission.at_least_editor"
:href="data.url.create"
@@ -150,6 +150,14 @@ defineProps({
</div>
</div>
<!-- no slices of life yet -->
<div
v-if="data.slices.length == 0"
class="mb-6 rounded-lg border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">
<img src="/img/journal_slice_of_life_blank.svg" :alt="$t('Journal')" class="mx-auto mt-4 h-14 w-14" />
<p class="px-5 pb-5 pt-2 text-center">Group journal entries together with slices of life.</p>
</div>
<div>
<inertia-link :href="data.url.slice_index" class="text-sm text-blue-500 hover:underline"
>View all slices</inertia-link
@@ -25,6 +25,8 @@ const form = useForm({
participants: [],
summary: null,
description: null,
distance: 0,
distance_unit: 'km',
});
const loadingState = ref(false);
@@ -34,8 +36,10 @@ const editDate = ref(false);
const modalShown = ref(false);
const addSummaryFieldShown = ref(false);
const addDescriptionFieldShown = ref(false);
const addDistanceFieldShown = ref(false);
const summaryField = ref(null);
const descriptionField = ref(null);
const distanceField = ref(null);
watch(
() => props.openModal,
@@ -55,8 +59,10 @@ const resetModal = () => {
form.summary = null;
form.description = null;
form.distance = 0;
addSummaryFieldShown.value = false;
addDescriptionFieldShown.value = false;
addDistanceFieldShown.value = false;
};
const loadTypes = (category) => {
@@ -92,6 +98,15 @@ const showAddDescriptionField = () => {
});
};
const showAddDistanceField = () => {
form.distance = null;
addDistanceFieldShown.value = true;
nextTick(() => {
distanceField.value.focus();
});
};
const store = () => {
loadingState.value = 'loading';
@@ -278,6 +293,57 @@ const store = () => {
:textarea-class="'block w-full'" />
</div>
<!-- description -->
<div
v-if="selectedLifeEventType && addDistanceFieldShown"
class="flex items-center border-b border-gray-200 pt-3 pb-1 pr-3 pl-3 dark:border-gray-700">
<text-input
ref="distanceField"
v-model="form.distance"
:label="'Distance'"
:type="'number'"
:autofocus="true"
:input-class="'mr-2'"
:required="false"
:autocomplete="false"
:help="'Enter a number from 0 to 100000. No decimals.'"
:min="0"
:max="100000"
@esc-key-pressed="addDistanceFieldShown = false" />
<ul>
<li class="mr-5 inline-block">
<div class="flex items-center">
<input
id="km"
v-model="form.distance_unit"
value="km"
name="distance_unit"
type="radio"
class="h-4 w-4 border-gray-300 text-sky-500 dark:border-gray-700" />
<label for="km" class="ml-1 block cursor-pointer text-sm font-medium text-gray-700 dark:text-gray-300">
km
</label>
</div>
</li>
<li class="inline-block">
<div class="flex items-center">
<input
id="miles"
v-model="form.distance_unit"
value="miles"
name="distance_unit"
type="radio"
class="h-4 w-4 border-gray-300 text-sky-500 dark:border-gray-700" />
<label for="miles" class="ml-1 block cursor-pointer text-sm font-medium text-gray-700 dark:text-gray-300">
miles
</label>
</div>
</li>
</ul>
</div>
<!-- options -->
<div v-if="selectedLifeEventType" class="flex flex-wrap border-b border-gray-200 p-3 dark:border-gray-700">
<!-- summary -->
@@ -297,6 +363,15 @@ const store = () => {
>+ description
</span>
</div>
<!-- distance -->
<div v-if="!addDistanceFieldShown">
<span
class="mr-2 mb-2 cursor-pointer rounded-lg border bg-slate-200 px-1 py-1 text-sm hover:bg-slate-300 dark:text-gray-900"
@click="showAddDistanceField"
>+ distance
</span>
</div>
</div>
<div class="flex justify-between p-5">
<pretty-span :text="$t('app.cancel')" :classes="'mr-3'" @click="$emit('closeModal')" />
+42 -14
View File
@@ -261,22 +261,50 @@ const toggleLifeEventVisibility = (lifeEvent) => {
{{ lifeEvent.description }}
</div>
<!-- date of life event -->
<!-- date of life event | distance -->
<div v-if="!lifeEvent.collapsed" class="flex items-center border-b border-gray-200 px-3 py-2 text-sm">
<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-500">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<!-- date -->
<div class="mr-4 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-2 h-4 w-4 text-gray-500">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
{{ lifeEvent.happened_at }}
{{ lifeEvent.happened_at }}
</div>
<!-- distance -->
<div v-if="lifeEvent.distance" class="flex items-center">
<svg
class="mr-2 h-6 w-6 text-gray-500"
viewBox="0 0 64 64"
xmlns="http://www.w3.org/2000/svg"
stroke-width="3"
stroke="#000000"
fill="none">
<path
d="M17.94,54.81a.1.1,0,0,1-.14,0c-1-1.11-11.69-13.23-11.69-21.26,0-9.94,6.5-12.24,11.76-12.24,4.84,0,11.06,2.6,11.06,12.24C28.93,41.84,18.87,53.72,17.94,54.81Z" />
<circle cx="17.52" cy="31.38" r="4.75" />
<path
d="M49.58,34.77a.11.11,0,0,1-.15,0c-.87-1-9.19-10.45-9.19-16.74,0-7.84,5.12-9.65,9.27-9.65,3.81,0,8.71,2,8.71,9.65C58.22,24.52,50.4,33.81,49.58,34.77Z" />
<circle cx="49.23" cy="17.32" r="3.75" />
<path d="M17.87,54.89a28.73,28.73,0,0,0,3.9.89" />
<path
d="M24.68,56.07c2.79.12,5.85-.28,7.9-2.08,5.8-5.09,2.89-11.25,6.75-14.71a16.72,16.72,0,0,1,4.93-3"
stroke-dasharray="7.8 2.92" />
<path d="M45.63,35.8a23,23,0,0,1,3.88-.95" />
</svg>
<span>{{ lifeEvent.distance }}</span>
</div>
</div>
<!-- participants -->
+2
View File
@@ -85,6 +85,7 @@ use App\Domains\Settings\ManageTemplates\Web\Controllers\PersonalizeTemplatePage
use App\Domains\Settings\ManageTemplates\Web\Controllers\PersonalizeTemplatesController;
use App\Domains\Settings\ManageUserPreferences\Web\Controllers\PreferencesController;
use App\Domains\Settings\ManageUserPreferences\Web\Controllers\PreferencesDateFormatController;
use App\Domains\Settings\ManageUserPreferences\Web\Controllers\PreferencesDistanceFormatController;
use App\Domains\Settings\ManageUserPreferences\Web\Controllers\PreferencesHelpController;
use App\Domains\Settings\ManageUserPreferences\Web\Controllers\PreferencesLocaleController;
use App\Domains\Settings\ManageUserPreferences\Web\Controllers\PreferencesMapsPreferenceController;
@@ -511,6 +512,7 @@ Route::middleware([
Route::post('date', [PreferencesDateFormatController::class, 'store'])->name('date.store');
Route::post('timezone', [PreferencesTimezoneController::class, 'store'])->name('timezone.store');
Route::post('number', [PreferencesNumberFormatController::class, 'store'])->name('number.store');
Route::post('distance', [PreferencesDistanceFormatController::class, 'store'])->name('distance.store');
Route::post('maps', [PreferencesMapsPreferenceController::class, 'store'])->name('maps.store');
Route::post('locale', [PreferencesLocaleController::class, 'store'])->name('locale.store');
Route::post('help', [PreferencesHelpController::class, 'store'])->name('help.store');
@@ -158,7 +158,8 @@ class CreateLifeEventTest extends TestCase
'currency_id' => null,
'paid_by_contact_id' => null,
'duration_in_minutes' => null,
'distance_in_km' => null,
'distance' => null,
'distance_unit' => null,
'from_place' => null,
'to_place' => null,
'place' => null,
@@ -196,7 +196,8 @@ class UpdateLifeEventTest extends TestCase
'currency_id' => null,
'paid_by_contact_id' => null,
'duration_in_minutes' => null,
'distance_in_km' => null,
'distance' => null,
'distance_unit' => null,
'from_place' => null,
'to_place' => null,
'place' => null,
@@ -193,7 +193,7 @@ class ModuleLifeEventViewHelperTest extends TestCase
$array = ModuleLifeEventViewHelper::dtoLifeEvent($lifeEvent, $user, $contact);
$this->assertEquals(
18,
19,
count($array)
);
@@ -207,7 +207,8 @@ class ModuleLifeEventViewHelperTest extends TestCase
$this->assertArrayHasKey('currency_id', $array);
$this->assertArrayHasKey('paid_by_contact_id', $array);
$this->assertArrayHasKey('duration_in_minutes', $array);
$this->assertArrayHasKey('distance_in_km', $array);
$this->assertArrayHasKey('distance', $array);
$this->assertArrayHasKey('distance_unit', $array);
$this->assertArrayHasKey('from_place', $array);
$this->assertArrayHasKey('to_place', $array);
$this->assertArrayHasKey('place', $array);
@@ -0,0 +1,69 @@
<?php
namespace Tests\Unit\Domains\Settings\ManageUserPreferences\Services;
use App\Domains\Settings\ManageUserPreferences\Services\StoreDistanceFormatPreference;
use App\Models\Account;
use App\Models\User;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Queue;
use Illuminate\Validation\ValidationException;
use Tests\TestCase;
class StoreDistanceFormatPreferenceTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function it_stores_the_distance_format_preference(): void
{
$ross = $this->createUser();
$this->executeService($ross, $ross->account);
}
/** @test */
public function it_fails_if_wrong_parameters_are_given(): void
{
$request = [
'title' => 'Ross',
];
$this->expectException(ValidationException::class);
(new StoreDistanceFormatPreference())->execute($request);
}
/** @test */
public function it_fails_if_user_doesnt_belong_to_account(): void
{
$this->expectException(ModelNotFoundException::class);
$ross = $this->createAdministrator();
$account = $this->createAccount();
$this->executeService($ross, $account);
}
private function executeService(User $author, Account $account): void
{
Queue::fake();
$request = [
'account_id' => $account->id,
'author_id' => $author->id,
'distance_format' => 'km',
];
$user = (new StoreDistanceFormatPreference())->execute($request);
$this->assertDatabaseHas('users', [
'id' => $user->id,
'account_id' => $account->id,
'distance_format' => 'km',
]);
$this->assertInstanceOf(
User::class,
$user
);
}
}
@@ -24,7 +24,7 @@ class UserPreferencesIndexViewHelperTest extends TestCase
$array = UserPreferencesIndexViewHelper::data($user);
$this->assertEquals(
8,
9,
count($array)
);
@@ -34,6 +34,7 @@ class UserPreferencesIndexViewHelperTest extends TestCase
$this->assertArrayHasKey('timezone', $array);
$this->assertArrayHasKey('url', $array);
$this->assertArrayHasKey('number_format', $array);
$this->assertArrayHasKey('distance_format', $array);
$this->assertArrayHasKey('maps', $array);
$this->assertArrayHasKey('locale', $array);
+57
View File
@@ -0,0 +1,57 @@
<?php
namespace Tests\Unit\Helpers;
use App\Helpers\DistanceHelper;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
class DistanceHelperTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function it_gets_the_distance_according_to_the_user_preference(): void
{
$distance = 134;
$unit = User::DISTANCE_UNIT_KM;
$user = User::factory()->create([
'distance_format' => User::DISTANCE_UNIT_KM,
]);
$this->assertEquals(
'134 km',
DistanceHelper::format($user, $distance, $unit)
);
$distance = 134;
$unit = User::DISTANCE_UNIT_MILES;
$user = User::factory()->create([
'distance_format' => User::DISTANCE_UNIT_KM,
]);
$this->assertEquals(
'215.65 km',
DistanceHelper::format($user, $distance, $unit)
);
$distance = 134;
$unit = User::DISTANCE_UNIT_MILES;
$user = User::factory()->create([
'distance_format' => User::DISTANCE_UNIT_MILES,
]);
$this->assertEquals(
'134 miles',
DistanceHelper::format($user, $distance, $unit)
);
$distance = 134;
$unit = User::DISTANCE_UNIT_KM;
$user = User::factory()->create([
'distance_format' => User::DISTANCE_UNIT_MILES,
]);
$this->assertEquals(
'83.26 miles',
DistanceHelper::format($user, $distance, $unit)
);
}
}