Skip to content

Commit 92bd597

Browse files
committed
use scheduled_at instead of schedule_in
1 parent 5d553a4 commit 92bd597

File tree

2 files changed

+98
-8
lines changed

2 files changed

+98
-8
lines changed

lib/algora/shared/util.ex

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,41 @@ defmodule Algora.Util do
203203

204204
String.contains?(s1, s2) or String.contains?(s2, s1)
205205
end
206+
207+
def next_occurrence_of_time(datetime) do
208+
now = DateTime.utc_now()
209+
210+
if DateTime.after?(datetime, now) do
211+
datetime
212+
else
213+
%{hour: hour, minute: minute, second: second, microsecond: microsecond} = datetime
214+
215+
now
216+
|> DateTime.truncate(:second)
217+
|> Map.put(:hour, hour)
218+
|> Map.put(:minute, minute)
219+
|> Map.put(:second, second)
220+
|> Map.put(:microsecond, microsecond)
221+
|> then(fn target_time ->
222+
if DateTime.after?(target_time, now) do
223+
target_time
224+
else
225+
DateTime.add(target_time, 24 * 60 * 60, :second)
226+
end
227+
end)
228+
end
229+
end
230+
231+
def random_datetime(opts \\ []) do
232+
now = DateTime.utc_now()
233+
from = Keyword.get(opts, :from, DateTime.add(now, -365, :day))
234+
to = Keyword.get(opts, :to, now)
235+
236+
from_unix = DateTime.to_unix(from)
237+
to_unix = DateTime.to_unix(to)
238+
239+
from_unix..to_unix
240+
|> Enum.random()
241+
|> DateTime.from_unix!()
242+
end
206243
end

lib/algora_web/live/admin/campaign_live.ex

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ defmodule AlgoraWeb.Admin.CampaignLive do
66
import Ecto.Changeset
77
import Ecto.Query
88

9+
alias Algora.Accounts
910
alias Algora.Activities.Jobs.SendCampaignEmail
1011
alias Algora.Admin
1112
alias Algora.Mailer
1213
alias Algora.Repo
1314
alias Algora.Settings
15+
alias Algora.Util
1416
alias Algora.Workspace
1517
alias Algora.Workspace.Repository
1618
alias AlgoraWeb.LocalStore
@@ -45,11 +47,15 @@ defmodule AlgoraWeb.Admin.CampaignLive do
4547

4648
@impl true
4749
def mount(_params, _session, socket) do
50+
timezone = if(params = get_connect_params(socket), do: params["timezone"])
51+
4852
{:ok,
4953
socket
54+
|> assign(:timezone, timezone)
5055
|> assign(:page_title, "Campaign")
5156
|> assign(:form, to_form(Campaign.changeset(%Campaign{})))
5257
|> assign(:repo_cache, %{})
58+
|> assign(:user_cache, %{})
5359
|> assign_preview()}
5460
end
5561

@@ -188,10 +194,12 @@ defmodule AlgoraWeb.Admin.CampaignLive do
188194
<.table id="csv-data" rows={@csv_data}>
189195
<:col
190196
:let={row}
191-
:for={key <- @csv_columns |> Enum.filter(&(&1 != "repo_url"))}
197+
:for={
198+
key <- @csv_columns |> Enum.filter(&(&1 != "repo_url" and &1 != "tech_stack"))
199+
}
192200
label={key}
193201
>
194-
<.cell value={row[key]} />
202+
<.cell value={row[key]} timezone={@timezone} />
195203
</:col>
196204
<:action :let={row}>
197205
<.button type="button" phx-click="send_email" phx-value-email={row["email"]}>
@@ -217,6 +225,17 @@ defmodule AlgoraWeb.Admin.CampaignLive do
217225
"""
218226
end
219227

228+
defp cell(%{value: %DateTime{}} = assigns) do
229+
~H"""
230+
<span :if={@timezone} class="tabular-nums whitespace-nowrap text-sm">
231+
{Calendar.strftime(
232+
DateTime.from_naive!(@value, "Etc/UTC") |> DateTime.shift_zone!(@timezone),
233+
"%Y/%m/%d, %H:%M:%S"
234+
)}
235+
</span>
236+
"""
237+
end
238+
220239
defp cell(assigns) do
221240
~H"""
222241
<span class="text-sm">
@@ -229,7 +248,7 @@ defmodule AlgoraWeb.Admin.CampaignLive do
229248
Enum.reduce(data, template, fn {key, value}, acc ->
230249
case value do
231250
value when is_list(value) -> acc
232-
_ -> String.replace(acc, "%{#{key}}", value)
251+
_ -> String.replace(acc, "%{#{key}}", to_string(value))
233252
end
234253
end)
235254
end
@@ -249,6 +268,39 @@ defmodule AlgoraWeb.Admin.CampaignLive do
249268

250269
defp repo_key(_row), do: nil
251270

271+
defp assign_timestamps(socket) do
272+
new_keys =
273+
socket.assigns.csv_data
274+
|> Enum.map(&Map.get(&1, "email"))
275+
|> Enum.uniq()
276+
277+
new_cache =
278+
Map.new(new_keys, fn key ->
279+
user = Accounts.get_user_by_email(key)
280+
281+
if user do
282+
{key, Util.next_occurrence_of_time(user.last_active_at || user.inserted_at)}
283+
else
284+
{key, Util.next_occurrence_of_time(Util.random_datetime())}
285+
end
286+
end)
287+
288+
updated_cache = Map.merge(socket.assigns.user_cache, new_cache)
289+
290+
csv_data =
291+
Enum.map(socket.assigns.csv_data, fn row -> Map.put(row, "timestamp", Map.get(updated_cache, row["email"])) end)
292+
293+
csv_columns =
294+
csv_data
295+
|> Enum.flat_map(&Map.keys/1)
296+
|> Enum.uniq()
297+
298+
socket
299+
|> assign(:repo_cache, updated_cache)
300+
|> assign(:csv_data, csv_data)
301+
|> assign(:csv_columns, csv_columns)
302+
end
303+
252304
defp assign_repo_names(socket) do
253305
new_keys =
254306
socket.assigns.csv_data
@@ -342,6 +394,7 @@ defmodule AlgoraWeb.Admin.CampaignLive do
342394
socket
343395
|> assign(:csv_data, csv_data)
344396
|> assign_repo_names()
397+
|> assign_timestamps()
345398
end
346399

347400
defp assign_preview(socket) do
@@ -374,16 +427,16 @@ defmodule AlgoraWeb.Admin.CampaignLive do
374427
id: Algora.Settings.get("email_campaign")["value"],
375428
subject: subject,
376429
recipient_email: recipient["email"],
377-
recipient: Algora.Util.term_to_base64(recipient),
430+
recipient: Util.term_to_base64(recipient),
378431
template: template,
379432
from_name: from_name,
380433
from_email: from_email,
381-
preheader: render_preview(preheader, recipient)
434+
preheader: render_preview(preheader, recipient),
435+
scheduled_at: recipient["timestamp"]
382436
}
383437
end)
384-
|> Enum.with_index()
385-
|> Enum.reduce_while(:ok, fn {args, index}, acc ->
386-
case args |> SendCampaignEmail.new(schedule_in: 5 * index) |> Oban.insert() do
438+
|> Enum.reduce_while(:ok, fn args, acc ->
439+
case args |> SendCampaignEmail.new(scheduled_at: args["scheduled_at"]) |> Oban.insert() do
387440
{:ok, _} -> {:cont, acc}
388441
{:error, _} -> {:halt, :error}
389442
end

0 commit comments

Comments
 (0)