Skip to content
Merged
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
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -349,4 +349,9 @@ MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/

**/App_Data/FShopOnWeb*
# SQLite database files
*.sqlite*

# App_Data directory - ignore all contents except .gitkeep
**/App_Data/*
!**/App_Data/.gitkeep
26 changes: 15 additions & 11 deletions src/Microsoft.eShopWeb.Web/Basket/Basket.Component.fs
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,23 @@ module BasketComponent =
section [ class' "esh-basket-item esh-basket-item--middle col" ] [ raw item.ProductName ]
section [ class' "esh-basket-item esh-basket-item--middle col" ] [ raw (item.UnitPrice.ToString "C") ]
section [ class' "esh-basket-item esh-basket-item--middle col" ] [ raw (item.Quantity.ToString()) ]
section [ class' "esh-basket-item esh-basket-item--middle col" ] [ raw ((decimal(item.Quantity) * item.UnitPrice).ToString "C" ) ] ] ]
section [ class' "esh-basket-item esh-basket-item--middle col" ] [ raw ((decimal(item.Quantity) * item.UnitPrice).ToString "C" ) ]
section [ class' "esh-basket-item esh-basket-item--middle col" ]
[ Elem.form
[ method "post"; action "/basket/remove" ]
[ input [ type' "hidden"; name "id"; value $"{item.CatalogItemId}" ]
input [ class' "btn btn-danger btn-sm"; type' "submit"; value "Remove" ] ] ] ] ]

let itemsTmpl items =
[ Elem.form
[ method "post" ]
[ article
[ class' "esh-basket-titles row row-cols-auto justify-content-between" ]
[ section [ class' "esh-basket-title col" ] [ raw "Product" ]
section [ class' "esh-basket-title col hidden-lg-down" ] []
section [ class' "esh-basket-title col" ] [ raw "Price" ]
section [ class' "esh-basket-title col" ] [ raw "Quantity" ]
section [ class' "esh-basket-title col" ] [ raw "Cost" ] ]
div [ class' "esh-catalog-items" ] (Seq.mapi itemTmpl items |> List.ofSeq) ] ]
[ article
[ class' "esh-basket-titles row row-cols-auto justify-content-between" ]
[ section [ class' "esh-basket-title col" ] [ raw "Product" ]
section [ class' "esh-basket-title col hidden-lg-down" ] []
section [ class' "esh-basket-title col" ] [ raw "Price" ]
section [ class' "esh-basket-title col" ] [ raw "Quantity" ]
section [ class' "esh-basket-title col" ] [ raw "Cost" ]
section [ class' "esh-basket-title col" ] [ raw "Actions" ] ]
div [ class' "esh-catalog-items" ] (Seq.mapi itemTmpl items |> List.ofSeq) ]

let noItemsTmpl =
[ h3 [ class' "esh-catalog-items row" ] [ raw "Basket is empty." ]
Expand Down
27 changes: 27 additions & 0 deletions src/Microsoft.eShopWeb.Web/Basket/Basket.Domain.fs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ module BasketDomain =
|> ignore
basket



let updateBasket (db: ShopContext) (quantity: int) productId =
async {
let! catalogItem =
Expand Down Expand Up @@ -96,3 +98,28 @@ module BasketDomain =
| None -> printfn "No product specified to be added to basket"
return None
}

let removeFromBasket (db: ShopContext) catalogItemId =
async {
let! existingBasket =
(db.Baskets.Include(fun b -> b.Items).OrderBy(fun b -> b.Id)) |> tryFirstAsync

let basket = existingBasket |> defaultValue emptyBasket

try
// Remove the basket item from the database
let itemToRemove =
db.BasketItems.Where(fun bi -> bi.CatalogItemId = catalogItemId && bi.BasketId = basket.Id)
|> Seq.tryHead

match itemToRemove with
| Some item ->
db.BasketItems.Remove(item) |> ignore
do! saveChangesAsync' db |> Async.Ignore
return Some catalogItemId
| None ->
return None
with exp ->
printfn $"Error removing item {catalogItemId} from basket"; printfn $"{exp}"
return None
}
15 changes: 15 additions & 0 deletions src/Microsoft.eShopWeb.Web/Basket/Basket.Page.fs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ module BasketPage =
| None -> Response.redirectPermanently "/basket?error=notfound"
| Some q -> Response.redirectPermanently $"/basket?added={q}"))

let remove: HttpHandler =
Services.inject<ShopContext> (fun db ->

let mapAsync = fun (form: FormCollectionReader) ->
form.TryGetGuid "id"
|> fun catalogItemId ->
match catalogItemId with
| Some id -> BasketDomain.removeFromBasket db id |> Async.StartAsTask
| None -> async { return None } |> Async.StartAsTask

Request.mapFormAsync mapAsync (fun result ->
match result with
| None -> Response.redirectPermanently "/basket?error=notfound"
| Some _ -> Response.redirectPermanently "/basket?removed=success"))

// This uses a more low-level approach to reading the form
let postAlternate: HttpHandler =
Services.inject<ShopContext> (fun db -> fun ctx ->
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.eShopWeb.Web/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ module Program =

get "/basket" BasketPage.get
post "/basket" BasketPage.post
post "/basket/remove" BasketPage.remove

get "/identity/account/login" LoginPage.handler

Expand Down
Loading
Loading