@fleetbase/fleetops-engine 0.4.12 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/addon/components/admin/avatar-management.hbs +78 -0
  2. package/addon/components/admin/avatar-management.js +191 -0
  3. package/addon/components/avatar-picker.hbs +15 -0
  4. package/addon/components/avatar-picker.js +57 -0
  5. package/addon/components/driver-form-panel.hbs +12 -13
  6. package/addon/components/driver-panel/details.hbs +7 -7
  7. package/addon/components/edit-order-route-panel.hbs +9 -69
  8. package/addon/components/edit-order-route-panel.js +78 -27
  9. package/addon/components/fleet-listing-panel.hbs +1 -1
  10. package/addon/components/layout/fleet-ops-sidebar/driver-listing.hbs +1 -1
  11. package/addon/components/layout/fleet-ops-sidebar.hbs +2 -1
  12. package/addon/components/live-map.js +0 -1
  13. package/addon/components/order/schedule-card.hbs +29 -17
  14. package/addon/components/order/schedule-card.js +1 -1
  15. package/addon/components/place-form-panel.hbs +35 -51
  16. package/addon/components/place-panel/details.hbs +10 -14
  17. package/addon/components/place-panel.hbs +2 -12
  18. package/addon/components/vehicle-form-panel.hbs +11 -80
  19. package/addon/components/vehicle-form-panel.js +33 -0
  20. package/addon/controllers/management/places/index.js +29 -21
  21. package/addon/controllers/operations/orders/index/view.js +10 -10
  22. package/addon/controllers/operations/scheduler/index.js +7 -4
  23. package/addon/engine.js +7 -1
  24. package/addon/styles/fleetops-engine.css +94 -0
  25. package/addon/templates/management/places/index.hbs +1 -1
  26. package/addon/templates/operations/scheduler/index.hbs +5 -4
  27. package/addon/utils/create-full-calendar-event-from-order.js +23 -1
  28. package/app/components/admin/avatar-management.js +1 -0
  29. package/app/components/avatar-picker.js +1 -0
  30. package/composer.json +2 -2
  31. package/config/environment.js +2 -0
  32. package/extension.json +1 -1
  33. package/package.json +3 -3
  34. package/server/migrations/2023_09_14_074512_update_vehicles_table.php +2 -2
  35. package/server/migrations/2023_09_14_074619_create_vehicle_devices_table.php +2 -2
  36. package/server/migrations/2023_09_26_071205_add_online_column_to_vehicles_table.php +2 -2
  37. package/server/migrations/2023_09_26_083957_create_fleet_vehicles_table.php +2 -2
  38. package/server/migrations/2023_09_27_023757_add_column_to_fleets_table.php +2 -2
  39. package/server/migrations/2023_10_05_074811_update_vehicle.php +2 -2
  40. package/server/migrations/2023_10_25_093014_create_vehicle_device_events_table.php +2 -2
  41. package/server/migrations/2023_11_03_072503_refactor_issues_table_columns.php +2 -2
  42. package/server/migrations/2023_11_06_040645_refactor_fuel_reports_table.php +2 -2
  43. package/server/migrations/2023_11_09_041807_add_status_column_to_fuel_reports_table.php +2 -2
  44. package/server/migrations/2023_11_15_062814_add_comments_column_and_resolved_at_column_to_vehicle_device_events_table.php +2 -2
  45. package/server/migrations/2023_11_17_053001_add_category_uuid_to_entities_table.php +2 -2
  46. package/server/migrations/2023_11_28_074244_add_supplier_uuid_column_to_entities_table.php +2 -2
  47. package/server/migrations/{2023_12_14_100209_add_meta_column_on_driver_table.php → 2023_12_14_100209_add_meta_column_on_driver_table copy.php } +5 -3
  48. package/server/migrations/2024_02_18_100209_add_avatar_url_columns_table.php +54 -0
  49. package/server/src/Expansions/UserExpansion.php +1 -0
  50. package/server/src/Http/Controllers/Api/v1/DriverController.php +7 -1
  51. package/server/src/Http/Controllers/Api/v1/PlaceController.php +11 -2
  52. package/server/src/Http/Controllers/Internal/v1/DriverController.php +15 -8
  53. package/server/src/Http/Controllers/Internal/v1/OrderController.php +46 -0
  54. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +12 -0
  55. package/server/src/Http/Resources/v1/Driver.php +6 -4
  56. package/server/src/Http/Resources/v1/Order.php +2 -1
  57. package/server/src/Http/Resources/v1/Payload.php +8 -4
  58. package/server/src/Http/Resources/v1/Place.php +2 -0
  59. package/server/src/Http/Resources/v1/Vehicle.php +1 -0
  60. package/server/src/Models/Driver.php +76 -0
  61. package/server/src/Models/Payload.php +49 -3
  62. package/server/src/Models/Place.php +71 -0
  63. package/server/src/Models/Vehicle.php +44 -20
  64. package/server/src/Notifications/OrderAssigned.php +2 -0
  65. package/server/src/routes.php +3 -0
  66. package/translations/en-us.yaml +16 -4
@@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration;
4
4
  use Illuminate\Database\Schema\Blueprint;
5
5
  use Illuminate\Support\Facades\Schema;
6
6
 
7
- class AddCategoryUuidToEntitiesTable extends Migration
7
+ return new class extends Migration
8
8
  {
9
9
  /**
10
10
  * Run the migrations.
@@ -30,4 +30,4 @@ class AddCategoryUuidToEntitiesTable extends Migration
30
30
  $table->dropColumn(['category_uuid']);
31
31
  });
32
32
  }
33
- }
33
+ };
@@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration;
4
4
  use Illuminate\Database\Schema\Blueprint;
5
5
  use Illuminate\Support\Facades\Schema;
6
6
 
7
- class AddSupplierUuidColumnToEntitiesTable extends Migration
7
+ return new class extends Migration
8
8
  {
9
9
  /**
10
10
  * Run the migrations.
@@ -30,4 +30,4 @@ class AddSupplierUuidColumnToEntitiesTable extends Migration
30
30
  $table->dropColumn(['supplier_uuid']);
31
31
  });
32
32
  }
33
- }
33
+ };
@@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration;
4
4
  use Illuminate\Database\Schema\Blueprint;
5
5
  use Illuminate\Support\Facades\Schema;
6
6
 
7
- class AddMetaColumnOnDriverTable extends Migration
7
+ return new class extends Migration
8
8
  {
9
9
  /**
10
10
  * Run the migrations.
@@ -25,6 +25,8 @@ class AddMetaColumnOnDriverTable extends Migration
25
25
  */
26
26
  public function down()
27
27
  {
28
- //
28
+ Schema::table('drivers', function (Blueprint $table) {
29
+ $table->dropColumn('meta');
30
+ });
29
31
  }
30
- }
32
+ };
@@ -0,0 +1,54 @@
1
+ <?php
2
+
3
+ use Illuminate\Database\Migrations\Migration;
4
+ use Illuminate\Database\Schema\Blueprint;
5
+ use Illuminate\Support\Facades\Schema;
6
+
7
+ return new class extends Migration
8
+ {
9
+ /**
10
+ * Run the migrations.
11
+ *
12
+ * @return void
13
+ */
14
+ public function up()
15
+ {
16
+ // Increase size of vehicles avatar url column for signed urls
17
+ Schema::table('vehicles', function (Blueprint $table) {
18
+ $table->mediumText('avatar_url')->change();
19
+ });
20
+
21
+ // Add avatar url column to places
22
+ Schema::table('places', function (Blueprint $table) {
23
+ $table->mediumText('avatar_url')->nullable()->after('remarks');
24
+ });
25
+
26
+ // Add avatar url column to drivers
27
+ Schema::table('drivers', function (Blueprint $table) {
28
+ $table->mediumText('avatar_url')->nullable()->after('signup_token_used');
29
+ });
30
+ }
31
+
32
+ /**
33
+ * Reverse the migrations.
34
+ *
35
+ * @return void
36
+ */
37
+ public function down()
38
+ {
39
+ // Reverse: Increase size of vehicles avatar url column for signed urls
40
+ Schema::table('vehicles', function (Blueprint $table) {
41
+ $table->string('avatar_url', 300)->change();
42
+ });
43
+
44
+ // Reverse: Add avatar url column to places
45
+ Schema::table('places', function (Blueprint $table) {
46
+ $table->dropColumn('avatar_url');
47
+ });
48
+
49
+ // Reverse: Add avatar url column to drivers
50
+ Schema::table('drivers', function (Blueprint $table) {
51
+ $table->dropColumn('avatar_url');
52
+ });
53
+ }
54
+ };
@@ -3,6 +3,7 @@
3
3
  namespace Fleetbase\FleetOps\Expansions;
4
4
 
5
5
  use Fleetbase\Build\Expansion;
6
+ use Fleetbase\FleetOps\Models\Contact;
6
7
  use Fleetbase\FleetOps\Models\Driver;
7
8
 
8
9
  class UserExpansion implements Expansion
@@ -58,7 +58,13 @@ class DriverController extends Controller
58
58
  $user = User::create($userDetails);
59
59
 
60
60
  // Assign company
61
- $user->assignCompany($company);
61
+ if ($company) {
62
+ $user->assignCompany($company);
63
+ } else {
64
+ $user->deleteQuietly();
65
+
66
+ return response()->apiError('Unable to assign driver to company.');
67
+ }
62
68
 
63
69
  // Set user type
64
70
  $user->setUserType('driver');
@@ -48,8 +48,11 @@ class PlaceController extends Controller
48
48
  'meta',
49
49
  ]);
50
50
 
51
+ // Check is missing key address attributes
52
+ $isNotAddressObject = $request->isNotFilled(['name', 'location', 'latititude', 'longitude', 'city', 'province', 'postal_code']);
53
+
51
54
  // if address param is sent create from mixed
52
- if ($request->isString('address')) {
55
+ if ($isNotAddressObject && $request->isString('address')) {
53
56
  $place = Place::createFromGeocodingLookup($request->input('address'));
54
57
 
55
58
  if ($place instanceof Place) {
@@ -58,7 +61,7 @@ class PlaceController extends Controller
58
61
  }
59
62
 
60
63
  // if street1 is the only param
61
- if ($request->missing(['name', 'location', 'latititude', 'longitude', 'address']) && $request->isString('street1')) {
64
+ if ($isNotAddressObject && $request->isString('street1')) {
62
65
  $place = Place::createFromGeocodingLookup($request->input('street1'));
63
66
 
64
67
  if ($place instanceof Place) {
@@ -129,6 +132,11 @@ class PlaceController extends Controller
129
132
  // check if missing location
130
133
  $isMissingLocation = empty($input['location']);
131
134
 
135
+ // set a default location for creation
136
+ if ($isMissingLocation) {
137
+ $input['location'] = new Point(0, 0);
138
+ }
139
+
132
140
  // fill place with attributes
133
141
  $place->fill($input);
134
142
 
@@ -145,6 +153,7 @@ class PlaceController extends Controller
145
153
  }
146
154
  }
147
155
 
156
+ // Save place
148
157
  $place->save();
149
158
 
150
159
  return new PlaceResource($place);
@@ -14,7 +14,6 @@ use Fleetbase\FleetOps\Models\Order;
14
14
  use Fleetbase\FleetOps\Support\Utils;
15
15
  use Fleetbase\Http\Requests\ExportRequest;
16
16
  use Fleetbase\LaravelMysqlSpatial\Types\Point;
17
- use Fleetbase\Models\CompanyUser;
18
17
  use Fleetbase\Models\Invite;
19
18
  use Fleetbase\Models\User;
20
19
  use Fleetbase\Models\VerificationCode;
@@ -176,13 +175,9 @@ class DriverController extends FleetOpsController
176
175
  // Assign user to company
177
176
  if ($company) {
178
177
  $user->assignCompany($company);
179
-
180
- // create company user
181
- CompanyUser::create([
182
- 'user_uuid' => $user->uuid,
183
- 'company_uuid' => $company->uuid,
184
- 'status' => 'active',
185
- ]);
178
+ } else {
179
+ $user->deleteQuietly();
180
+ throw new \Exception('Unable to assign driver to company.');
186
181
  }
187
182
 
188
183
  // Set user type as driver
@@ -305,6 +300,18 @@ class DriverController extends FleetOpsController
305
300
  return response()->json($statuses);
306
301
  }
307
302
 
303
+ /**
304
+ * Get all avatar options for an vehicle.
305
+ *
306
+ * @return \Illuminate\Http\Response
307
+ */
308
+ public function avatars()
309
+ {
310
+ $options = Driver::getAvatarOptions();
311
+
312
+ return response()->json($options);
313
+ }
314
+
308
315
  /**
309
316
  * Export the drivers to excel or csv.
310
317
  *
@@ -142,6 +142,52 @@ class OrderController extends FleetOpsController
142
142
  }
143
143
  }
144
144
 
145
+ /**
146
+ * Route which enables editing of an order route.
147
+ *
148
+ * @param string $id - The order ID.
149
+ * @param Request $request
150
+ * @return Response
151
+ */
152
+ public function editOrderRoute(string $id, Request $request) {
153
+ $pickup = $request->input('pickup');
154
+ $dropoff = $request->input('dropoff');
155
+ $return = $request->input('return');
156
+ $waypoints = $request->array('waypoints', []);
157
+
158
+ // Get the order
159
+ $order = Order::where('uuid', $id)->with(['payload'])->first();
160
+ if (!$order) {
161
+ return response()->error('Unable to find order to update route for.');
162
+ }
163
+
164
+ // Handle update of multiple waypoints
165
+ if ($waypoints) {
166
+ $order->payload->updateWaypoints($waypoints);
167
+ $order->payload->removePlace(['pickup', 'dropoff', 'return'], ['save' => true]);
168
+ } else {
169
+ // Update pickup
170
+ if ($pickup) {
171
+ $order->payload->setPickup($pickup, ['save' => true]);
172
+ }
173
+
174
+ // Update dropoff
175
+ if ($dropoff) {
176
+ $order->payload->setDropoff($dropoff, ['save' => true]);
177
+ }
178
+
179
+ // Update return
180
+ if ($return) {
181
+ $order->payload->setDropoff($return, ['save' => true]);
182
+ }
183
+
184
+ // Remove waypoints if any
185
+ $order->payload->removeWaypoints();
186
+ }
187
+
188
+ return ['order' => new $this->resource($order)];
189
+ }
190
+
145
191
  /**
146
192
  * Process import files (excel,csv) into Fleetbase order data.
147
193
  *
@@ -160,4 +160,16 @@ class PlaceController extends FleetOpsController
160
160
  200
161
161
  );
162
162
  }
163
+
164
+ /**
165
+ * Get all avatar options for an vehicle.
166
+ *
167
+ * @return \Illuminate\Http\Response
168
+ */
169
+ public function avatars()
170
+ {
171
+ $options = Place::getAvatarOptions();
172
+
173
+ return response()->json($options);
174
+ }
163
175
  }
@@ -29,10 +29,12 @@ class Driver extends FleetbaseResource
29
29
  'public_id' => $this->when(Http::isInternalRequest(), $this->public_id),
30
30
  'internal_id' => $this->internal_id,
31
31
  'name' => $this->name,
32
- 'email' => $this->email ?? null,
33
- 'phone' => $this->phone ?? null,
34
- 'drivers_license_number' => $this->drivers_license_number ?? null,
35
- 'photo_url' => $this->photo_url ?? null,
32
+ 'email' => $this->email,
33
+ 'phone' => $this->phone,
34
+ 'drivers_license_number' => $this->drivers_license_number,
35
+ 'photo_url' => $this->photo_url,
36
+ 'avatar_url' => $this->avatar_url,
37
+ 'avatar_value' => $this->when(Http::isInternalRequest(), $this->getOriginal('avatar_url')),
36
38
  'vehicle_name' => $this->when(Http::isInternalRequest(), $this->vehicle_name),
37
39
  'vehicle_avatar' => $this->when(Http::isInternalRequest(), $this->vehicle_avatar),
38
40
  'vendor_name' => $this->when(Http::isInternalRequest(), $this->vendor_name),
@@ -4,6 +4,7 @@ namespace Fleetbase\FleetOps\Http\Resources\v1;
4
4
 
5
5
  use Fleetbase\FleetOps\Support\Utils;
6
6
  use Fleetbase\Http\Resources\Comment;
7
+ use Fleetbase\Http\Resources\File;
7
8
  use Fleetbase\Http\Resources\FleetbaseResource;
8
9
  use Fleetbase\Support\Http;
9
10
  use Fleetbase\Support\Resolve;
@@ -45,7 +46,7 @@ class Order extends FleetbaseResource
45
46
  'tracking_number' => new TrackingNumber($this->trackingNumber),
46
47
  'tracking_statuses' => $this->whenLoaded('trackingStatuses', TrackingStatus::collection($this->trackingStatuses)),
47
48
  'comments' => $this->when(Http::isInternalRequest(), Comment::collection($this->comments)),
48
- 'files' => $this->when(Http::isInternalRequest(), $this->files),
49
+ 'files' => $this->when(Http::isInternalRequest(), $this->files, File::collection($this->files)),
49
50
  'purchase_rate' => new PurchaseRate($this->purchaseRate),
50
51
  'notes' => $this->notes,
51
52
  'type' => $this->type,
@@ -41,11 +41,15 @@ class Payload extends FleetbaseResource
41
41
 
42
42
  private function getWaypoints(): ?\Illuminate\Support\Collection
43
43
  {
44
- return $this->waypoints->map(function ($waypoint) {
45
- $waypoint->payload_uuid = $this->uuid;
44
+ if ($this->waypoints instanceof \Illuminate\Support\Collection) {
45
+ return $this->waypoints->map(function ($waypoint) {
46
+ $waypoint->payload_uuid = $this->uuid;
46
47
 
47
- return $waypoint;
48
- });
48
+ return $waypoint;
49
+ });
50
+ }
51
+
52
+ return [];
49
53
  }
50
54
 
51
55
  /**
@@ -26,6 +26,8 @@ class Place extends FleetbaseResource
26
26
  'location' => data_get($this, 'location', new Point(0, 0)),
27
27
  'address' => $this->address,
28
28
  'address_html' => $this->when(Http::isInternalRequest(), $this->address_html),
29
+ 'avatar_url' => $this->avatar_url,
30
+ 'avatar_value' => $this->when(Http::isInternalRequest(), $this->getOriginal('avatar_url')),
29
31
  'street1' => $this->street1 ?? null,
30
32
  'street2' => $this->street2 ?? null,
31
33
  'city' => $this->city ?? null,
@@ -29,6 +29,7 @@ class Vehicle extends FleetbaseResource
29
29
  'devices' => $this->whenLoaded('devices', $this->devices),
30
30
  'photo_url' => $this->photo_url,
31
31
  'avatar_url' => $this->avatar_url,
32
+ 'avatar_value' => $this->when(Http::isInternalRequest(), $this->getOriginal('avatar_url')),
32
33
  'make' => $this->make,
33
34
  'model' => $this->model,
34
35
  'year' => $this->year,
@@ -8,6 +8,7 @@ use Fleetbase\FleetOps\Scopes\DriverScope;
8
8
  use Fleetbase\FleetOps\Support\Utils;
9
9
  use Fleetbase\FleetOps\Support\Utils as FleetOpsUtils;
10
10
  use Fleetbase\LaravelMysqlSpatial\Eloquent\SpatialTrait;
11
+ use Fleetbase\Models\File;
11
12
  use Fleetbase\Models\Model;
12
13
  use Fleetbase\Traits\HasApiModelBehavior;
13
14
  use Fleetbase\Traits\HasInternalId;
@@ -77,6 +78,7 @@ class Driver extends Model
77
78
  'current_job_uuid',
78
79
  'auth_token',
79
80
  'signup_token_used',
81
+ 'avatar_url',
80
82
  'drivers_license_number',
81
83
  'location',
82
84
  'heading',
@@ -295,6 +297,80 @@ class Driver extends Model
295
297
  return $this->hasMany(\Fleetbase\Models\UserDevice::class, 'user_uuid', 'user_uuid');
296
298
  }
297
299
 
300
+ /**
301
+ * Get avatar url.
302
+ *
303
+ * @return string|null
304
+ */
305
+ public function getAvatarUrlAttribute($value)
306
+ {
307
+ // if vehicle assigned us the vehicle avatar
308
+ if ($this->vehicle) {
309
+ return $this->vehicle->avatar_url;
310
+ }
311
+
312
+ if (!$value) {
313
+ return static::getAvatar();
314
+ }
315
+
316
+ if (Str::isUuid($value)) {
317
+ return static::getAvatar($value);
318
+ }
319
+
320
+ return $value;
321
+ }
322
+
323
+ /**
324
+ * Get an avatar url by key.
325
+ *
326
+ * @param string $key
327
+ */
328
+ public static function getAvatar($key = 'moto-driver'): ?string
329
+ {
330
+ if (Str::isUuid($key)) {
331
+ $file = File::where('uuid', $key)->first();
332
+ if ($file) {
333
+ return $file->url;
334
+ }
335
+
336
+ return null;
337
+ }
338
+
339
+ return static::getAvatarOptions()->get($key);
340
+ }
341
+
342
+ /**
343
+ * Get all avatar options for a vehicle.
344
+ *
345
+ * @return \Illuminate\Support\Collection
346
+ */
347
+ public static function getAvatarOptions()
348
+ {
349
+ $options = [
350
+ 'moto-driver.png',
351
+ ];
352
+
353
+ // Get custom avatars
354
+ $customAvatars = collect(File::where('type', 'driver-avatar')->get()->mapWithKeys(
355
+ function ($file) {
356
+ $key = str_replace(['.svg', '.png'], '', 'Custom: ' . $file->original_filename);
357
+
358
+ return [$key => $file->uuid];
359
+ }
360
+ )->toArray());
361
+
362
+ // Create default avatars included from fleetbase
363
+ $avatars = collect($options)->mapWithKeys(
364
+ function ($option) {
365
+ $key = str_replace(['.svg', '.png'], '', $option);
366
+
367
+ return [$key => Utils::assetFromS3('static/driver-icons/' . $option)];
368
+ }
369
+ );
370
+
371
+ return $customAvatars->merge($avatars);
372
+ }
373
+
298
374
  /**
299
375
  * Specifies the user's FCM tokens.
300
376
  *
@@ -578,10 +578,47 @@ class Payload extends Model
578
578
  }
579
579
 
580
580
  $this->load('order');
581
-
582
581
  return $this->order;
583
582
  }
584
583
 
584
+ public function removeWaypoints()
585
+ {
586
+ Waypoint::where('payload_uuid', $this->uuid)->delete();
587
+ $this->setRelation('waypoints', collect());
588
+ return $this;
589
+ }
590
+
591
+ public function removePlace($property, array $options = [])
592
+ {
593
+ // remove multiple places
594
+ if (is_array($property)) {
595
+ foreach ($property as $prop) {
596
+ if (is_string($prop)) {
597
+ $this->removePlace($prop, $options);
598
+ }
599
+ }
600
+
601
+ return $this;
602
+ }
603
+
604
+ $attr = $property . '_uuid';
605
+ $save = data_get($options, 'save', false);
606
+ $callback = data_get($options, 'callback', false);
607
+
608
+ $this->setAttribute($attr, null);
609
+ $this->setRelation($property, null);
610
+
611
+ if ($save) {
612
+ $this->updateQuietly([$attr => null]);
613
+ }
614
+
615
+ if (is_callable($callback)) {
616
+ $callback($this);
617
+ }
618
+
619
+ return $this;
620
+ }
621
+
585
622
  public function setPlace($property, Place $place, array $options = [])
586
623
  {
587
624
  $attr = $property . '_uuid';
@@ -599,8 +636,17 @@ class Payload extends Model
599
636
  }
600
637
  }
601
638
 
639
+ // Get the ID property
640
+ $id = $this->{$attr};
641
+
642
+ // set relationship to model instance to
643
+ if ($instance instanceof Model) {
644
+ $this->setRelation($property, $instance);
645
+ }
646
+
647
+ // If optioned to save
602
648
  if ($save) {
603
- $this->save();
649
+ $this->updateQuietly([$attr => $id]);
604
650
  }
605
651
 
606
652
  if (is_callable($callback)) {
@@ -673,7 +719,7 @@ class Payload extends Model
673
719
  }
674
720
 
675
721
  $this->current_waypoint_uuid = $destination->uuid;
676
- $this->save();
722
+ $this->saveQuietly();
677
723
  $this->updateWaypointActivity($activity, $location);
678
724
 
679
725
  return $this->load('currentWaypoint');
@@ -7,6 +7,7 @@ use Fleetbase\FleetOps\Casts\Point;
7
7
  use Fleetbase\FleetOps\Support\Geocoding;
8
8
  use Fleetbase\FleetOps\Support\Utils;
9
9
  use Fleetbase\LaravelMysqlSpatial\Eloquent\SpatialTrait;
10
+ use Fleetbase\Models\File;
10
11
  use Fleetbase\Models\Model;
11
12
  use Fleetbase\Traits\HasApiModelBehavior;
12
13
  use Fleetbase\Traits\HasMetaAttributes;
@@ -69,6 +70,7 @@ class Place extends Model
69
70
  'company_uuid',
70
71
  'owner_uuid',
71
72
  'owner_type',
73
+ 'avatar_url',
72
74
  'name',
73
75
  'type',
74
76
  'street1',
@@ -168,6 +170,75 @@ class Place extends Model
168
170
  return data_get($this, 'country_data.name.common');
169
171
  }
170
172
 
173
+ /**
174
+ * Get avatar url.
175
+ *
176
+ * @return string|null
177
+ */
178
+ public function getAvatarUrlAttribute($value)
179
+ {
180
+ if (!$value) {
181
+ return static::getAvatar();
182
+ }
183
+
184
+ if (Str::isUuid($value)) {
185
+ return static::getAvatar($value);
186
+ }
187
+
188
+ return $value;
189
+ }
190
+
191
+ /**
192
+ * Get an avatar url by key.
193
+ *
194
+ * @param string $key
195
+ */
196
+ public static function getAvatar($key = 'basic-building'): ?string
197
+ {
198
+ if (Str::isUuid($key)) {
199
+ $file = File::where('uuid', $key)->first();
200
+ if ($file) {
201
+ return $file->url;
202
+ }
203
+
204
+ return null;
205
+ }
206
+
207
+ return static::getAvatarOptions()->get($key);
208
+ }
209
+
210
+ /**
211
+ * Get all avatar options for a vehicle.
212
+ *
213
+ * @return \Illuminate\Support\Collection
214
+ */
215
+ public static function getAvatarOptions()
216
+ {
217
+ $options = [
218
+ 'basic-building.png',
219
+ ];
220
+
221
+ // Get custom avatars
222
+ $customAvatars = collect(File::where('type', 'place-avatar')->get()->mapWithKeys(
223
+ function ($file) {
224
+ $key = str_replace(['.svg', '.png'], '', 'Custom: ' . $file->original_filename);
225
+
226
+ return [$key => $file->uuid];
227
+ }
228
+ )->toArray());
229
+
230
+ // Create default avatars included from fleetbase
231
+ $avatars = collect($options)->mapWithKeys(
232
+ function ($option) {
233
+ $key = str_replace(['.svg', '.png'], '', $option);
234
+
235
+ return [$key => Utils::assetFromS3('static/place-icons/' . $option)];
236
+ }
237
+ );
238
+
239
+ return $customAvatars->merge($avatars);
240
+ }
241
+
171
242
  /**
172
243
  * Returns a Point instance from the location of the model.
173
244
  */