diff --git a/app/Domains/Contact/ManageLifeEvents/Services/CreateLifeEvent.php b/app/Domains/Contact/ManageLifeEvents/Services/CreateLifeEvent.php
index da5df0581..dac8c9d69 100644
--- a/app/Domains/Contact/ManageLifeEvents/Services/CreateLifeEvent.php
+++ b/app/Domains/Contact/ManageLifeEvents/Services/CreateLifeEvent.php
@@ -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'),
diff --git a/app/Domains/Contact/ManageLifeEvents/Services/UpdateLifeEvent.php b/app/Domains/Contact/ManageLifeEvents/Services/UpdateLifeEvent.php
index cd7007ef2..65bdcaeea 100644
--- a/app/Domains/Contact/ManageLifeEvents/Services/UpdateLifeEvent.php
+++ b/app/Domains/Contact/ManageLifeEvents/Services/UpdateLifeEvent.php
@@ -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');
diff --git a/app/Domains/Contact/ManageLifeEvents/Web/Controllers/ContactModuleLifeEventController.php b/app/Domains/Contact/ManageLifeEvents/Web/Controllers/ContactModuleLifeEventController.php
index b3a773374..5da18d8c3 100644
--- a/app/Domains/Contact/ManageLifeEvents/Web/Controllers/ContactModuleLifeEventController.php
+++ b/app/Domains/Contact/ManageLifeEvents/Web/Controllers/ContactModuleLifeEventController.php
@@ -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'),
diff --git a/app/Domains/Contact/ManageLifeEvents/Web/Controllers/ContactModuleTimelineEventController.php b/app/Domains/Contact/ManageLifeEvents/Web/Controllers/ContactModuleTimelineEventController.php
index 12edda14a..b35dab78d 100644
--- a/app/Domains/Contact/ManageLifeEvents/Web/Controllers/ContactModuleTimelineEventController.php
+++ b/app/Domains/Contact/ManageLifeEvents/Web/Controllers/ContactModuleTimelineEventController.php
@@ -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'),
diff --git a/app/Domains/Contact/ManageLifeEvents/Web/ViewHelpers/ModuleLifeEventViewHelper.php b/app/Domains/Contact/ManageLifeEvents/Web/ViewHelpers/ModuleLifeEventViewHelper.php
index e72ee469b..c0a11f2c1 100644
--- a/app/Domains/Contact/ManageLifeEvents/Web/ViewHelpers/ModuleLifeEventViewHelper.php
+++ b/app/Domains/Contact/ManageLifeEvents/Web/ViewHelpers/ModuleLifeEventViewHelper.php
@@ -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,
diff --git a/app/Domains/Settings/ManageUserPreferences/Services/StoreDistanceFormatPreference.php b/app/Domains/Settings/ManageUserPreferences/Services/StoreDistanceFormatPreference.php
new file mode 100644
index 000000000..127448bfd
--- /dev/null
+++ b/app/Domains/Settings/ManageUserPreferences/Services/StoreDistanceFormatPreference.php
@@ -0,0 +1,53 @@
+ '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();
+ }
+}
diff --git a/app/Domains/Settings/ManageUserPreferences/Web/Controllers/PreferencesDistanceFormatController.php b/app/Domains/Settings/ManageUserPreferences/Web/Controllers/PreferencesDistanceFormatController.php
new file mode 100644
index 000000000..da57fbb2f
--- /dev/null
+++ b/app/Domains/Settings/ManageUserPreferences/Web/Controllers/PreferencesDistanceFormatController.php
@@ -0,0 +1,27 @@
+ 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);
+ }
+}
diff --git a/app/Domains/Settings/ManageUserPreferences/Web/ViewHelpers/UserPreferencesIndexViewHelper.php b/app/Domains/Settings/ManageUserPreferences/Web/ViewHelpers/UserPreferencesIndexViewHelper.php
index 811a12b92..ac0eabc9d 100644
--- a/app/Domains/Settings/ManageUserPreferences/Web/ViewHelpers/UserPreferencesIndexViewHelper.php
+++ b/app/Domains/Settings/ManageUserPreferences/Web/ViewHelpers/UserPreferencesIndexViewHelper.php
@@ -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();
diff --git a/app/Helpers/DistanceHelper.php b/app/Helpers/DistanceHelper.php
new file mode 100644
index 000000000..c6162cfe5
--- /dev/null
+++ b/app/Helpers/DistanceHelper.php
@@ -0,0 +1,22 @@
+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]);
+ }
+}
diff --git a/app/Models/LifeEvent.php b/app/Models/LifeEvent.php
index f2d4f6f91..d9b486414 100644
--- a/app/Models/LifeEvent.php
+++ b/app/Models/LifeEvent.php
@@ -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',
diff --git a/app/Models/User.php b/app/Models/User.php
index f98fd7940..0c857dfe6 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -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',
diff --git a/database/factories/LifeEventFactory.php b/database/factories/LifeEventFactory.php
index 7d5b5aab1..43872b719 100644
--- a/database/factories/LifeEventFactory.php
+++ b/database/factories/LifeEventFactory.php
@@ -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(),
diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php
index 3babdda87..7b46aa22a 100644
--- a/database/migrations/2014_10_12_000000_create_users_table.php
+++ b/database/migrations/2014_10_12_000000_create_users_table.php
@@ -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);
diff --git a/database/migrations/2022_05_17_155546_create_life_events_table.php b/database/migrations/2022_05_17_155546_create_life_events_table.php
index 32bcc10c4..9a2aae4e6 100644
--- a/database/migrations/2022_05_17_155546_create_life_events_table.php
+++ b/database/migrations/2022_05_17_155546_create_life_events_table.php
@@ -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();
diff --git a/lang/en/app.php b/lang/en/app.php
index 76b4b5a87..7e44d0ef8 100644
--- a/lang/en/app.php
+++ b/lang/en/app.php
@@ -133,4 +133,7 @@ return [
'min_read' => '{count} min read',
'word_count' => '{count} words',
+
+ 'distance_format_km' => ':distance km',
+ 'distance_format_mi' => ':distance miles',
];
diff --git a/lang/en/settings.php b/lang/en/settings.php
index b40e832ba..0902a0e1c 100644
--- a/lang/en/settings.php
+++ b/lang/en/settings.php
@@ -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:',
diff --git a/resources/js/Pages/Settings/Preferences/Index.vue b/resources/js/Pages/Settings/Preferences/Index.vue
index 6e5aaf32c..0180cf8cf 100644
--- a/resources/js/Pages/Settings/Preferences/Index.vue
+++ b/resources/js/Pages/Settings/Preferences/Index.vue
@@ -43,6 +43,8 @@
+ {{ $t('settings.user_preferences_number_format_description') }}
+ {{
+ localDistanceFormat
+ }}
+
+ ✈️
+
+ {{ $t('settings.user_preferences_distance_format_title') }}
+
+
+
+
Group journal entries together with slices of life.
+