Skip to content

Instantly share code, notes, and snippets.

@eyJhb
Created February 11, 2025 20:23
Show Gist options
  • Save eyJhb/204c8e1bc9da981edd9b6e2a0bfd5745 to your computer and use it in GitHub Desktop.
Save eyJhb/204c8e1bc9da981edd9b6e2a0bfd5745 to your computer and use it in GitHub Desktop.
Elm split module
module Main exposing (main)
import Basics
import Browser
import Browser.Events
import Colors
import Element as E exposing (Element)
import Element.Background as Background
import Element.Font as Font
import Html exposing (Html, button, div, text)
import Offers
import Platform.Cmd exposing (Cmd, batch)
main : Program Screen Model Msg
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- subscriptions
subscriptions : Model -> Sub Msg
subscriptions model =
Browser.Events.onResize <|
\width height ->
DeviceClassified { width = width, height = height }
-- MODEL
type alias Model =
{ device : E.Device
, screen : Screen
, offersModel : Offers.Model
}
type alias Screen =
{ width : Int
, height : Int
}
init : Screen -> ( Model, Cmd Msg )
init screen =
let
( initialOffersModel, initialOffersCmd ) =
Offers.init
in
( { device = E.classifyDevice screen
, screen = screen
, offersModel = initialOffersModel
}
, Cmd.map OffersMsg initialOffersCmd
)
-- UPDATE
type Msg
= DeviceClassified Screen
| OffersMsg Offers.Msg
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
DeviceClassified screen ->
( { model
| device = E.classifyDevice { width = screen.width, height = screen.height }
, screen = screen
}
, Cmd.none
)
OffersMsg t ->
let
( newOffersModel, offersCmds ) =
Offers.update t model.offersModel
in
( { model | offersModel = newOffersModel }, Cmd.map OffersMsg offersCmds )
view : Model -> Html Msg
view model =
-- initial setup
E.layout
[ E.width (E.px model.screen.width)
, E.height (E.px model.screen.height)
, Background.color (E.rgba 0 0 0 1)
, Font.color Colors.white
, Font.size 18
, Font.family
[ Font.external
{ url = "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"
, name = "Inter"
}
]
]
<|
-- actual site content
E.column
[ E.width E.fill
, E.height E.fill
, Background.gradient { angle = Basics.pi, steps = [ Colors.backgroundPrimary, Colors.backgroundSecondary ] }
]
[ E.el
[ E.width E.fill
, E.padding 10
, Font.bold
, Font.size 50
, Font.center
]
(E.text "Bilka+")
, E.row
[]
[ E.map OffersMsg (Offers.viewPersonalisedDiscounts model.offersModel) ]
-- [ E.text "lol" ]
-- [ viewPersonalisedDiscounts model ]
-- -- personalised discounts
-- , E.el [ E.padding 10, Font.bold, Font.size 25, Font.underline ] (E.text "Personalised Discounts")
-- , E.el [ E.width E.fill, E.height E.fill ] (viewPersonalisedDiscounts model)
-- -- member discounts
-- , E.el [ E.padding 10, Font.bold, Font.size 25, Font.underline ] (E.text "Membership Discounts")
-- , E.el [ E.width E.fill, E.height E.fill ] (viewMembershipOffers model)
]
module Offers exposing (..)
import Element as E exposing (Element)
import Http
import Json.Decode as D exposing (Decoder)
import Json.Decode.Pipeline as DP
import Platform.Cmd exposing (Cmd, batch)
import RemoteData
import Time
type alias Model =
{ personalDiscounts : RemoteData.WebData (List PersonalisedOffer)
}
type Msg
= GotPersonalisedDiscounts (RemoteData.WebData (List PersonalisedOffer))
init : ( Model, Cmd Msg )
init =
( { personalDiscounts = RemoteData.NotAsked
}
, batch
[ fetchPersonalisedOffers
]
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotPersonalisedDiscounts o ->
( { model
| personalDiscounts = o
}
, Cmd.none
)
fetchPersonalisedOffers : Cmd Msg
fetchPersonalisedOffers =
Http.get
{ url = "http://192.168.1.30:1746/api_offers.json"
, expect = Http.expectJson (RemoteData.fromResult >> GotPersonalisedDiscounts) decoderPersonalisedOffer
}
type alias PersonalisedOffer =
{ id : String
, articleNumber : String
, title : String
, description : String
, imageURL : String
, originalPrice : Float
, discountedPrice : Float
, startDate : Time.Posix
, endDate : Time.Posix
, variants : List OfferVariant
}
type alias OfferVariant =
{ title : String
, articleNumber : String
, description : String
, imageURL : String
}
decoderPersonalisedOffer : D.Decoder (List PersonalisedOffer)
decoderPersonalisedOffer =
D.list
(D.succeed PersonalisedOffer
|> DP.required "id" D.string
|> DP.required "articleNumber" D.string
|> DP.required "title" D.string
|> DP.required "description" D.string
|> DP.required "offerImage" D.string
|> DP.required "originalPrice" D.float
|> DP.required "discountedPrice" D.float
|> DP.required "startDate" decoderTimestamp
|> DP.required "endDate" decoderTimestamp
|> DP.required "variants"
(D.list
(D.succeed OfferVariant
|> DP.required "title" D.string
|> DP.required "articleNumber" D.string
|> DP.required "description" D.string
|> DP.required "imageUrl" D.string
)
)
)
decoderTimestamp : Decoder Time.Posix
decoderTimestamp =
-- look at community json extra datetime for example of below
-- --
-- could be done like the below as well for a one-off
-- |> DP.required "endDate" (D.andThen (\millis -> D.succeed (Time.millisToPosix millis)) D.int)
D.andThen
(\dateString ->
-- case Iso8601.toTime dateString of
D.succeed (Time.millisToPosix dateString)
)
D.int
viewPersonalisedDiscounts : Model -> Element Msg
viewPersonalisedDiscounts model =
case model.personalDiscounts of
RemoteData.NotAsked ->
E.text "Initialising..."
RemoteData.Loading ->
E.text "Loading..."
RemoteData.Failure err ->
E.text ("Error: " ++ Debug.toString err)
RemoteData.Success offers ->
E.row
[ E.width E.fill
, E.scrollbarY
, E.spacing 20
]
[ E.text (Debug.toString offers) ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment