Skip to content

Commit

Permalink
feat: /vote page (#2211)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshlarson authored Nov 1, 2024
1 parent 1557acb commit 0487889
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 4 deletions.
3 changes: 2 additions & 1 deletion assets/css/_autocomplete-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@
#error-page,
#proposed-sales-locations,
#sales-locations,
#transit-near-me-locations {
#transit-near-me-locations,
#vote {
--aa-search-input-height: 2.5rem;

.aa-Form {
Expand Down
3 changes: 2 additions & 1 deletion assets/ts/ui/autocomplete/__tests__/helpers-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ test("itemWithUrl gets a requested URL", () => {
urls: {
"transit-near-me": "/transit-near-me/logan",
"retail-sales-locations": "/retail-locations-somewhere",
"proposed-sales-locations": "/proposed-locations-near-logan"
"proposed-sales-locations": "/proposed-locations-near-logan",
vote: "/vote"
}
} as WithUrls<PopularItem>;
const item2 = itemWithUrl(item, "retail-sales-locations");
Expand Down
18 changes: 18 additions & 0 deletions assets/ts/ui/autocomplete/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,23 @@ const PROPOSED_RETAIL: Partial<AutocompleteOptions<any>> = {
}
};

/**
* This configuration is used for finding polling locations
*/
const VOTE: Partial<AutocompleteOptions<any>> = {
...baseOptions,
initialState: {
query: getLikelyQueryParams()
},
getSources({ query }): AutocompleteSource<any>[] {
if (!query) return debounced([]);
return debounced([locationSource(query, 5, "vote")]);
},
onReset: (): void => {
window.location.assign(`/vote`);
}
};

/**
* This configuration is intended for use within a form, and will update form
* values or internal LiveView state instead of navigating to any URL. Further
Expand Down Expand Up @@ -229,6 +246,7 @@ const ALL: Record<string, (...args: any) => ConfigurationOptions> = {
"transit-near-me": () => TNM,
"retail-locations": () => RETAIL,
"proposed-locations": () => PROPOSED_RETAIL,
vote: () => VOTE,
"trip-planner": TRIP_PLANNER
};

Expand Down
3 changes: 2 additions & 1 deletion assets/ts/ui/autocomplete/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ export const getTitleAttribute = (item: Item): string[] => {
export type UrlType =
| "transit-near-me"
| "retail-sales-locations"
| "proposed-sales-locations";
| "proposed-sales-locations"
| "vote";

export type WithUrls<T> = T & { urls: Record<UrlType, string> };

Expand Down
2 changes: 2 additions & 0 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ config :dotcom, DotcomWeb.ViewHelpers,
google_tag_manager_auth: System.get_env("GOOGLE_TAG_MANAGER_AUTH"),
google_tag_manager_preview: System.get_env("GOOGLE_TAG_MANAGER_PREVIEW")

config :dotcom, google_api_key: System.get_env("GOOGLE_API_KEY")

config :recaptcha,
public_key: System.get_env("RECAPTCHA_PUBLIC_KEY"),
secret: System.get_env("RECAPTCHA_PRIVATE_KEY", "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe")
Expand Down
14 changes: 13 additions & 1 deletion lib/dotcom_web/controllers/places_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,17 @@ defmodule DotcomWeb.PlacesController do
Map.take(map, [:latitude, :longitude])
end

vote_params =
case map do
%{formatted: formatted} ->
map
|> Map.take([:latitude, :longitude])
|> Map.put(:address, formatted)

_ ->
%{}
end

map
|> Map.put_new(:urls, %{
"retail-sales-locations" =>
Expand All @@ -165,7 +176,8 @@ defmodule DotcomWeb.PlacesController do
:show_transformation,
params
),
"transit-near-me" => transit_near_me_path(DotcomWeb.Endpoint, :index, params)
"transit-near-me" => transit_near_me_path(DotcomWeb.Endpoint, :index, params),
"vote" => vote_path(DotcomWeb.Endpoint, :show, vote_params)
})
end

Expand Down
83 changes: 83 additions & 0 deletions lib/dotcom_web/controllers/vote_controller.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
defmodule DotcomWeb.VoteController do
@moduledoc """
Handles rendering the vote widget
"""

use DotcomWeb, :controller

import DotcomWeb.ViewHelpers, only: [cms_static_page_path: 2]

plug(:meta_description)
plug(:clear_polling_results)

def show(
conn,
%{"address" => address, "latitude" => latitude, "longitude" => longitude} = _params
) do
google_api_key = Application.get_env(:dotcom, :google_api_key)

response =
Req.get("https://www.googleapis.com/civicinfo/v2/voterinfo",
params: [
key: google_api_key,
electionId: "9000",
address: address
]
)

conn =
case response do
{:ok, %{body: %{"pollingLocations" => [polling_location | _]}}} ->
polling_location_name = Recase.to_title(polling_location["address"]["locationName"])

params = %{
"plan" => %{
"from_latitude" => latitude,
"from_longitude" => longitude,
"from" => address,
"to_latitude" => polling_location["latitude"],
"to_longitude" => polling_location["longitude"],
"to" => polling_location_name
}
}

conn
|> assign(:polling_location, polling_location)
|> assign(:polling_location_name, polling_location_name)
|> assign(:trip_plan_path, trip_plan_path(DotcomWeb.Endpoint, :index, params))

_ ->
conn |> assign(:polling_error, true)
end

conn
|> assign(:should_scroll, true)
|> assign(:breadcrumbs, [
Breadcrumb.build("Take the T to Vote", cms_static_page_path(conn, "/vote"))
])
|> render("show.html")
end

def show(conn, _params) do
conn
|> assign(:breadcrumbs, [
Breadcrumb.build("Vote", cms_static_page_path(conn, "/vote"))
])
|> render("show.html")
end

defp meta_description(conn, _) do
conn
|> assign(
:meta_description,
"Tuesday, November 5 is the last day to vote in the 2024 general election. Use the T to get to your polling location."
)
end

defp clear_polling_results(conn, _) do
conn
|> assign(:polling_location, nil)
|> assign(:polling_error, false)
|> assign(:should_scroll, false)
end
end
2 changes: 2 additions & 0 deletions lib/dotcom_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ defmodule DotcomWeb.Router do
for static_page <- StaticPage.static_pages() do
get("/#{StaticPage.convert_path(static_page)}", StaticPageController, static_page)
end

get("/vote", VoteController, :show)
end

scope "/", DotcomWeb do
Expand Down
93 changes: 93 additions & 0 deletions lib/dotcom_web/templates/vote/show.html.heex
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<div class="container m-sales-locations">
<div class="col-md-8">
<div class="limited-width">
<h1>Take the T to Vote</h1>
<img
class="image-style-max-2600x2600 c-media__element img-fluid mb-6"
src="https://cdn.mbta.com/sites/default/files/styles/max_2600x2600/public/media/2021-03/2017-28-06-downtown-crossing-flags.jpg?itok=GqEXce3F"
alt="An exterior shot of the Downtown Crossing Station entrance. US Flags line the street, and skyscrapers are visible in the background. Many pedestrians are walking by "
/>

<p>
Tuesday, November 5 is the last day to vote in the 2024
general election. Use the T to get to your polling location.
</p>
</div>

<div
id="polling-place-form"
class="mb-6"
{if @should_scroll, do: %{"phx-hook" => "ScrollIntoView"}, else: %{}}
>
<h2 class="mb-6">Find Your Polling Place</h2>

<p class="font-bold mb-1">Home Address</p>
<.algolia_autocomplete
id="vote"
config_type="vote"
placeholder="Enter your registered address"
/>
</div>

<div :if={@polling_location != nil}>
<p class="font-bold mb-1">Your Polling Place</p>

<div class="u-highlight-gray border border-silver-100 rounded-md flex flex-col p-6">
<div class="font-bold text-lg mb-2">
<%= @polling_location_name %>
</div>
<div class="mb-6">
<%= @polling_location["address"]["line1"] %>
<br />
<%= @polling_location["address"]["city"] %>, <%= @polling_location["address"]["state"] %>
<%= @polling_location["address"]["zip"] %>
</div>
<a class="btn btn-primary" href={@trip_plan_path}>
Plan your trip
</a>
</div>
</div>

<div :if={@polling_error} class="flex flex-col">
<p class="italic">
We weren't able to find a polling place for your address. You
can also visit the
<a href="https://www.sec.state.ma.us/WhereDoIVoteMA/WhereDoIVote" target="_blank">
Secretary of State's official site
</a>
to find your polling place, and then use the
<a href={trip_plan_path(DotcomWeb.Endpoint, :index)} target="_blank">
MBTA Trip Planner
</a>
to plan your trip.
</p>
</div>
</div>

<div class="col-md-4">
<div class="m-schedule-page__schedule-notes u-mt-2">
<h2 class="mt-0">More Guides</h2>
<figure class="c-media c-media--image c-media--wide">
<div class="c-media__content">
<a class="c-media__link" href="/guides" target="">
<img
class="image-style-max-2600x2600 c-media__element img-fluid"
src="https://cdn.mbta.com/sites/default/files/styles/max_2600x2600/public/media/2019-01/meta-guide-MORE-WORDS.png?itok=akfxoExc"
alt="Clickable graphic for User Guides"
/>
</a>
</div>
</figure>

<p>
Our user guides can help you learn how to navigate the system,
get to local events, use accessibility features, and more.
</p>
<%= link("View all guides",
to: cms_static_page_path(@conn, "/guides"),
target: "_blank",
class: "c-call-to-action"
) %>
</div>
</div>
</div>
6 changes: 6 additions & 0 deletions lib/dotcom_web/views/vote_view.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
defmodule DotcomWeb.VoteView do
@moduledoc """
View for the vote widget
"""
use DotcomWeb, :view
end

0 comments on commit 0487889

Please sign in to comment.