Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
query OrganizationAgentLocations($agentId: ID!) {
user {
organization {
agent(agentId: $agentId) {
id
name
user {
phone
}
places {
id
name
description
lat
lng
createdAt
}
locations {
id
position
createdAt
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
query OrganizationPerformance($start: Date!, $end: Date!) {
user {
organization {
performance(start: $start, end: $end) {
id
name
places {
id
name
description
lat
lng
createdAt
}
locations {
id
position
createdAt
}
}
}
}
}
3 changes: 3 additions & 0 deletions dispatch/resources/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ type Organization {
vehicles: [Vehicle]
plans: [Plan]
plan(planId: ID!): Plan
performance(start: Date!, end: Date!): [Agent]
}

type Agent {
id: ID!
name: String!
user: User
location: Location
locations: [Location]
places: [Place]
place(placeId: ID!, filters: TaskFilters): Place
tasks(filters: TaskFilters): [Task]
Expand Down Expand Up @@ -109,6 +111,7 @@ type Place {
lat: Float!
lng: Float!
tasks: [Task]
createdAt: Date
}

type Stop {
Expand Down
155 changes: 155 additions & 0 deletions dispatch/scripts/find-routes.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

const user = await prisma.user.findUnique({
where: { email: "[email protected]" },
include: {
organization: {
include: {
places: {
include: {
agent: true,
},
},
agents: {
include: {
locations: {
orderBy: {
createdAt: "asc",
},
},
},
},
},
},
},
});

const places = user.organization.places;

// group places by created day
const places_by_day = places.reduce((acc, place) => {
const date = place.createdAt.toISOString().slice(0, 10);
if (!acc[date]) {
acc[date] = [];
}
acc[date].push(place);
return acc;
}, {});

// group places by day by agent
const places_by_day_by_agent = Object.entries(places_by_day).map(
([date, places]) => [
new Date(date).toLocaleDateString("es-AR", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
}),
places.reduce((acc, place) => {
const agent = place.agent;
if (!agent) {
return acc;
}
if (!acc[agent.name]) {
acc[agent.name] = [];
}
acc[agent.name].push(place.name);
return acc;
}, {}),
]
);

function haversine(lat1, lon1, lat2, lon2) {
function toRad(degree) {
return (degree * Math.PI) / 180;
}

const R = 6371; // Earth's radius in kilometers
const dLat = toRad(lat2 - lat1);
const dLon = toRad(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(lat1)) *
Math.cos(toRad(lat2)) *
Math.sin(dLon / 2) *
Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

return R * c;
}

function totalDistanceTraveled(locations) {
let totalDistance = 0;

for (let i = 0; i < locations.length - 1; i++) {
const loc1 = locations[i];
const loc2 = locations[i + 1];

const distance = haversine(
loc1.latitude,
loc1.longitude,
loc2.latitude,
loc2.longitude
);
totalDistance += distance;
}

return totalDistance;
}

// const places_by_day_by_agent_with_distance = places_by_day_by_agent.map(
// ([date, places_by_agent]) => [
// date,
// Object.entries(places_by_agent).map(([agent_name, places]) => [
// agent_name,
// places,
// user.organization.agents
// .find((agent) => {
// // console.log(agent);
// return agent.name === agent_name;
// })
// .locations.filter(
// (location) =>
// new Date(location.createdAt).toLocaleDateString("es-AR", {
// weekday: "long",
// year: "numeric",
// month: "long",
// day: "numeric",
// }) === date
// )
// .map((location) => {
// // console.log(location);
// return location.position;
// }).length,
// ]),
// ]
// );

const agent_locations_by_day = user.organization.agents.map((agent) => {
const locations_by_day = agent.locations.reduce((acc, location) => {
const date = location.createdAt.toISOString().slice(0, 10);
if (!acc[date]) {
acc[date] = [];
}
acc[date].push(location);
return acc;
}, {});

return [
agent.name,
Object.entries(locations_by_day).map(([date, locations]) => [
new Date(date).toLocaleDateString("es-AR", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
}),
locations.length,
totalDistanceTraveled(locations.map((location) => location.position)),
]),
];
});

console.log(JSON.stringify(agent_locations_by_day));
3 changes: 2 additions & 1 deletion dispatch/src/api/lib/apollo.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@
:organization #()
:agent #()}
:Organization
{:agents agent/fetch-organization-agents
{:performance agent/fetch-organization-performance
:agents agent/fetch-organization-agents
:agent agent/fetch-organization-agent
:places place/fetch-organization-places
:place place/fetch-organization-place
Expand Down
25 changes: 21 additions & 4 deletions dispatch/src/api/models/agent.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
(.forEach
agents
(fn [^js agent]
(set! (.-location agent) (first (.-locations agent)))))
(set! (.-location agent) (last (.-locations agent)))))
;; this moves null values to the end of the list
(sort-by #(some-> ^js % .-location .-createdAt) > agents)))

Expand All @@ -47,11 +47,28 @@
{:where {:id agentId}
:include
{:user true
:locations {:take 1
:orderBy {:createdAt "desc"}}
:places {:orderBy {:createdAt "asc"}}
:locations {:orderBy {:createdAt "asc"}}
:tasks {:where (filters/task filters)
:orderBy {:startAt "asc"}
:include {:stops {:include {:place true}}}}}}}}}})
^js agent (first (.. result -organization -agents))]
(set! (.-location agent) (first (.. agent -locations)))
(set! (.-location agent) (last (.. agent -locations)))
agent))

(defn fetch-organization-performance [^js context {:keys [start end]}]
(p/let [^js user (active-user
context
{:include
{:organization
{:include
{:agents
{:include
{:user true
:places
{:where {:createdAt {:gte start :lte end}}
:orderBy {:createdAt "asc"}}
:locations
{:where {:createdAt {:gte start :lte end}}
:orderBy {:createdAt "asc"}}}}}}}})]
(.. user -organization -agents)))
4 changes: 4 additions & 0 deletions dispatch/src/api/resolvers/agent.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@
(defn fetch-organization-agent
[_ args context _]
(agent/fetch-organization-agent context (->clj args)))

(defn fetch-organization-performance
[_ args context _]
(agent/fetch-organization-performance context (->clj args)))
5 changes: 3 additions & 2 deletions dispatch/src/api/resolvers/place.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
(place/fetch-organization-place context (->clj args)))

(defn fetch-agent-places
[_ _ context _]
(place/fetch-agent-places context))
[^js parent _ context _]
(or (.. parent -places)
(place/fetch-agent-places context)))

(defn fetch-agent-place
[_ args context _]
Expand Down
7 changes: 7 additions & 0 deletions dispatch/src/ui/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
[trim-v]
(assoc-key :map))

(rf/reg-event-db
:map/locations
[trim-v]
(fn [db [v]]
(assoc-in
db [:map :locations] v)))

(rf/reg-event-db
:layout/toggle-nav
(fn [db]
Expand Down
31 changes: 20 additions & 11 deletions dispatch/src/ui/hooks/use_map.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[ui.lib.google.maps.core :refer (init-api)]
[ui.lib.google.maps.polyline :refer (set-polylines clear-polylines decode-polyline)]
[ui.lib.google.maps.marker :refer (set-markers clear-markers)]
[ui.lib.google.maps.overlay :refer (set-overlays clear-overlays)]
[ui.lib.google.maps.overlay :refer (update-overlays)]
[ui.utils.location :refer (position-to-lat-lng)]))

(def ^:private !el (atom nil))
Expand Down Expand Up @@ -60,16 +60,24 @@

(useEffect
(fn []
(if @!map (let [polylines (when (seq paths) (set-polylines @!map paths))
markers (when (seq points) (set-markers @!map points))
overlays (when (or (seq locations) position)
(set-overlays @!map (remove nil? (conj locations position))))]
#(do
(clear-polylines polylines)
(clear-markers markers)
(clear-overlays overlays)))
(if @!map (let [polylines (when (seq paths) (set-polylines @!map paths))]
#(clear-polylines polylines))
#()))
#js[@!map paths points locations position])
#js[@!map (js/JSON.stringify paths)])

(useEffect
(fn []
(if @!map (let [markers (when (seq points) (set-markers @!map points))]
#(clear-markers markers))
#()))
#js[@!map (js/JSON.stringify points)])

(useEffect
(fn []
(when @!map
(update-overlays @!map (remove nil? (conj locations position)))
#()))
#js[@!map locations position])

{:ref map-ref
:center center}))
Expand All @@ -96,9 +104,10 @@
(filterv
some?
(mapv
(fn [{:keys [lat lng name]}]
(fn [{:keys [lat lng name color]}]
(when (and lat lng)
{:title (or name "???")
:color color
:position {:lat lat :lng lng}}))
places))
:locations
Expand Down
Loading