Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: delete draft detour backend #2925

Merged
merged 23 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
108d8d5
feat: delete draft detour UI
bfauble Dec 11, 2024
4a4b336
Merge branch 'main' into bf-delete-draft-detour
bfauble Dec 11, 2024
ea81020
rm console.log and format
bfauble Dec 11, 2024
19106f2
Merge branch 'bf-delete-draft-detour' of https://github.com/mbta/skat…
bfauble Dec 11, 2024
e0a0f2b
address comments
bfauble Jan 3, 2025
9269214
format
bfauble Jan 10, 2025
c8aeebb
Merge branch 'main' into bf-delete-draft-detour
bfauble Jan 13, 2025
d6b5efc
wip
bfauble Jan 14, 2025
b6842ed
Merge branch 'main' into bf-delete-draft-detour-backend
bfauble Jan 16, 2025
8d74e35
Setup delete draft callback and server side detour deletion. Pub even…
bfauble Jan 17, 2025
39701a3
Merge branch 'main' into bf-delete-draft-detour-backend
bfauble Jan 17, 2025
b8af669
Merge branch 'main' into bf-delete-draft-detour-backend
bfauble Jan 23, 2025
360cef9
update state machine config
bfauble Jan 23, 2025
634267d
fix type and use camelCase instead of snake
bfauble Jan 23, 2025
eabae43
format and move deleted target to top level
bfauble Jan 23, 2025
8825d0c
add elixir tests
bfauble Jan 23, 2025
047ab47
Merge branch 'main' into bf-delete-draft-detour-backend
bfauble Jan 23, 2025
68e2c54
Merge branch 'main' into bf-delete-draft-detour-backend
bfauble Jan 23, 2025
e113b96
Merge branch 'main' into bf-delete-draft-detour-backend
bfauble Jan 24, 2025
32e2ac9
add frontend test for delete detour flow
bfauble Jan 24, 2025
1aa29fc
format
bfauble Jan 24, 2025
974e173
fix broken tests
bfauble Jan 24, 2025
34285f6
Update assets/tests/components/detours/diversionPage.delete.test.tsx
bfauble Jan 24, 2025
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
18 changes: 18 additions & 0 deletions assets/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
any,
array,
assert,
boolean,
create,
enums,
Infer,
Expand Down Expand Up @@ -556,6 +557,23 @@ export const fetchDetour = (
ErrStruct: never(),
}).then((v) => map(v, detourStateFromData))

export const deleteDetour = (
id: number | undefined
): Promise<Result<boolean, never>> => {
return apiCallResult({
url: `/api/detours/${id}`,
OkStruct: boolean(),
ErrStruct: never(),
requestInit: {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"x-csrf-token": getCsrfToken(),
},
},
})
}

// #endregion Detour API functions

const getCsrfToken = (): string => appData()?.csrfToken || ""
Expand Down
31 changes: 23 additions & 8 deletions assets/src/components/detours/diversionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, {
ComponentProps,
ComponentPropsWithoutRef,
PropsWithChildren,
useCallback,
useContext,
useState,
} from "react"
Expand Down Expand Up @@ -32,6 +33,7 @@ import useScreenSize from "../../hooks/useScreenSize"
import { Drawer } from "../drawer"
import { isMobile } from "../../util/screenSize"
import { AffectedRoute } from "./detourPanelComponents"
import { deleteDetour } from "../../api"

const displayFieldsFromRouteAndPattern = (
route: Route,
Expand Down Expand Up @@ -118,6 +120,15 @@ export const DiversionPage = ({
: { input: useDetourProps.originalRoute }
)

const deleteDetourCallback = useCallback(() => {
if (snapshot.context.uuid) {
deleteDetour(snapshot.context.uuid).then(() => {
onClose()
return send({ type: "detour.delete.delete-modal.delete-draft" })
})
}
}, [onClose, send, snapshot.context.uuid])

const nearestIntersectionDirection = [
{ instruction: "From " + nearestIntersection },
]
Expand Down Expand Up @@ -171,7 +182,11 @@ export const DiversionPage = ({
}
}

const detourPanel = () => {
const detourPanel: ({
deleteDetourCallback,
}: {
deleteDetourCallback: () => void
}) => React.JSX.Element = () => {
if (snapshot.matches({ "Detour Drawing": "Pick Route Pattern" })) {
return (
<DetourRouteSelectionPanel
Expand Down Expand Up @@ -273,7 +288,7 @@ export const DiversionPage = ({
: undefined
}
onDeleteDetour={
inTestGroup(TestGroups.DeleteDraftDetours)
inTestGroup(TestGroups.DeleteDraftDetours) && snapshot.context.uuid
? () => {
send({ type: "detour.delete.open-delete-modal" })
}
Expand Down Expand Up @@ -376,13 +391,11 @@ export const DiversionPage = ({

{snapshot.matches({
"Detour Drawing": {
"Share Detour": "Deleting",
"Share Detour": { Deleting: "Confirming" },
},
}) ? (
<DeleteDetourModal
onDelete={() =>
send({ type: "detour.delete.delete-modal.delete-draft" })
}
onDelete={deleteDetourCallback}
onCancel={() =>
send({ type: "detour.delete.delete-modal.cancel" })
}
Expand Down Expand Up @@ -518,9 +531,11 @@ export const DiversionPage = ({
])}
>
{isMobile(displayType) ? (
<Drawer.WithState startOpen>{detourPanel()}</Drawer.WithState>
<Drawer.WithState startOpen>
{detourPanel({ deleteDetourCallback })}
</Drawer.WithState>
) : (
detourPanel()
detourPanel({ deleteDetourCallback })
)}
</div>
<div className="l-diversion-page__map position-relative">
Expand Down
17 changes: 17 additions & 0 deletions assets/src/hooks/useDetours.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const subscribe = (
handleDrafted: ((data: SimpleDetour) => void) | undefined,
handleActivated: ((data: SimpleDetour) => void) | undefined,
handleDeactivated: ((data: SimpleDetour) => void) | undefined,
handleDeleted: ((detour_id: number) => void) | undefined,
initialMessageType: typeof SimpleDetourData | typeof ActivatedDetourData
): Channel => {
const channel = socket.channel(topic)
Expand All @@ -43,6 +44,12 @@ const subscribe = (
const data = create(unknownData, SimpleDetourData)
handleDeactivated(simpleDetourFromData(data))
})
handleDeleted &&
channel.on("deleted", ({ data: detour_id }: { data: unknown }) => {
if (typeof detour_id === "number") {
handleDeleted(detour_id)
}
})
channel.on("auth_expired", reload)

channel
Expand Down Expand Up @@ -107,6 +114,7 @@ export const useActiveDetours = (socket: Socket | undefined) => {
undefined,
handleActivated,
handleDeactivated,
undefined,
ActivatedDetourData
)
}
Expand Down Expand Up @@ -140,6 +148,7 @@ export const usePastDetours = (socket: Socket | undefined) => {
undefined,
undefined,
handleDeactivated,
undefined,
SimpleDetourData
)
}
Expand Down Expand Up @@ -170,6 +179,13 @@ export const useDraftDetours = (socket: Socket | undefined) => {
})
}

const handleDeleted = (detour_id: number) => {
setDraftDetours((draftDetours) => {
delete draftDetours[detour_id]
return draftDetours
})
}

useEffect(() => {
let channel: Channel | undefined
if (socket) {
Expand All @@ -180,6 +196,7 @@ export const useDraftDetours = (socket: Socket | undefined) => {
handleDrafted,
handleActivated,
undefined,
handleDeleted,
SimpleDetourData
)
}
Expand Down
14 changes: 11 additions & 3 deletions assets/src/models/createDetourMachine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ export const createDetourMachine = setup({
finishedDetour: undefined,
detourShape: undefined,
}),
"detour.deleted": assign(() => ({})),
},
}).createMachine({
id: "Detours Machine",
Expand Down Expand Up @@ -657,17 +658,24 @@ export const createDetourMachine = setup({
Confirming: {
on: {
"detour.delete.delete-modal.delete-draft": {
target: "Done",
tags: "no-save",
target: "Deleted",
actions: "detour.deleted",
},
},
},
Done: { type: "final" },
Deleted: {
tags: "no-save",
target: ".onDone",
},
Done: { tags: "no-save", type: "final" },
},
onDone: {
target: "Done",
target: "DoneNoSave",
},
},
Done: { type: "final" },
DoneNoSave: { tags: "no-save", type: "final" },
},
onDone: {
target: "Active",
Expand Down
32 changes: 32 additions & 0 deletions lib/skate/detours/detours.ex
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,22 @@ defmodule Skate.Detours.Detours do
"""
def get_detour!(id), do: Repo.get!(Detour, id)

@doc """
Gets a single detour authored by the provided user_id.

Raises `Ecto.NoResultsError` if the Detour does not exist.

## Examples

iex> get_detour_for_user!(123, 123)
%Detour{}

iex> get_detour_for_user!(456, 123)
** (Ecto.NoResultsError)

"""
def get_detour_for_user!(id, user_id), do: Repo.get_by!(Detour, id: id, author_id: user_id)

@doc """
Gets a single detour with state intact.

Expand Down Expand Up @@ -248,6 +264,22 @@ defmodule Skate.Detours.Detours do
detour_db_result
end

@spec delete_draft_detour(Detour.t(), DbUser.id()) :: :ok
def delete_draft_detour(detour, author_id) do
author_uuid =
author_id
|> User.get_by_id!()
|> Map.get(:uuid)

{:ok, _} = delete_detour(detour)

Phoenix.PubSub.broadcast(
Skate.PubSub,
"detours:draft:" <> author_uuid,
{:draft_detour_deleted, detour.id}
)
end

@spec broadcast_detour(detour_type(), Detour.t(), DbUser.id()) :: :ok
defp broadcast_detour(:draft, detour, author_id) do
author_uuid =
Expand Down
6 changes: 6 additions & 0 deletions lib/skate_web/channels/detours_channel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,10 @@ defmodule SkateWeb.DetoursChannel do
:ok = push(socket, "drafted", %{data: detour})
{:noreply, socket}
end

@impl SkateWeb.AuthenticatedChannel
def handle_info_authenticated({:draft_detour_deleted, detour_id}, socket) do
:ok = push(socket, "deleted", %{data: detour_id})
{:noreply, socket}
end
end
9 changes: 9 additions & 0 deletions lib/skate_web/controllers/detours_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ defmodule SkateWeb.DetoursController do
end
end

@spec delete_detour(Plug.Conn.t(), map()) :: Plug.Conn.t()
def delete_detour(conn, %{"detour_id" => detour_id}) do
%{id: user_id} = AuthManager.Plug.current_resource(conn)
detour = Detours.get_detour_for_user!(detour_id, user_id)
:ok = Detours.delete_draft_detour(detour, user_id)

json(conn, %{data: true})
end

defp format(%RouteSegments.UnfinishedResult{
before_start_point: before_start_point,
after_start_point: after_start_point
Expand Down
1 change: 1 addition & 0 deletions lib/skate_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ defmodule SkateWeb.Router do
get "/location_search/suggest", LocationSearchController, :suggest
get "/detours", DetoursController, :detours
get "/detours/:detour_id", DetoursController, :detour
delete "/detours/:detour_id", DetoursController, :delete_detour
post "/detours/directions/", DetourRouteController, :directions
put "/detours/update_snapshot", DetoursController, :update_snapshot
post "/detours/unfinished_detour", DetoursController, :unfinished_detour
Expand Down
Loading