diff --git a/src/elm/Auth.elm b/src/elm/Auth.elm index f49164955..09051dbcf 100755 --- a/src/elm/Auth.elm +++ b/src/elm/Auth.elm @@ -56,8 +56,8 @@ import View.Pin as Pin -- INIT -init : Maybe Eos.PrivateKey -> Model -init maybePrivateKey_ = +init : Bool -> Maybe Eos.PrivateKey -> Model +init pinVisibility maybePrivateKey_ = let status = case maybePrivateKey_ of @@ -69,7 +69,7 @@ init maybePrivateKey_ = in { status = status , error = Nothing - , pinModel = initPinModel status + , pinModel = initPinModel pinVisibility status } @@ -84,14 +84,15 @@ type alias Model = } -initPinModel : Status -> Pin.Model -initPinModel status = +initPinModel : Bool -> Status -> Pin.Model +initPinModel pinVisibility status = Pin.init { label = "auth.pinPopup.label" , id = "pinPopup" , withConfirmation = False , submitLabel = "auth.login.continue" , submittingLabel = "auth.login.continue" + , pinVisibility = pinVisibility } |> Pin.withDisabled (case status of @@ -182,6 +183,7 @@ type alias SignInResponse = type ExternalMsg = CompletedAuth SignInResponse Model + | UpdatedShared Shared update : Msg -> Shared -> Model -> UpdateResult @@ -194,10 +196,14 @@ update msg shared model = let ( newPinModel, submitStatus ) = Pin.update subMsg model.pinModel + + ( newShared, submitCmd ) = + Pin.postSubmitAction newPinModel submitStatus shared SubmittedPin in { model | pinModel = newPinModel } |> UR.init - |> UR.addCmd (Pin.maybeSubmitCmd submitStatus SubmittedPin) + |> UR.addCmd submitCmd + |> UR.addExt (UpdatedShared newShared) CompletedSignIn status (RemoteData.Success (Just ({ token } as signInResponse))) -> let @@ -311,7 +317,7 @@ authFailed error model = | status = WithoutPrivateKey , error = Nothing , pinModel = - initPinModel model.status + initPinModel model.pinModel.isPinVisible model.status |> Pin.withProblem Pin.Pin error } |> UR.init diff --git a/src/elm/Flags.elm b/src/elm/Flags.elm index e7ea9585f..01357286a 100755 --- a/src/elm/Flags.elm +++ b/src/elm/Flags.elm @@ -26,6 +26,7 @@ type alias Flags = , canReadClipboard : Bool , useSubdomain : Bool , selectedCommunity : Maybe Eos.Symbol + , pinVisibility : Bool } @@ -45,6 +46,7 @@ default = , canReadClipboard = False , useSubdomain = True , selectedCommunity = Nothing + , pinVisibility = False } @@ -72,6 +74,7 @@ decode = |> required "canReadClipboard" Decode.bool |> required "useSubdomain" Decode.bool |> required "selectedCommunity" (Decode.nullable Eos.symbolDecoder) + |> required "pinVisibility" Decode.bool type alias Endpoints = diff --git a/src/elm/Main.elm b/src/elm/Main.elm index 449af4786..95744ed95 100755 --- a/src/elm/Main.elm +++ b/src/elm/Main.elm @@ -771,6 +771,11 @@ updateGuestUResult toStatus toMsg model uResult = ( { m | session = Page.Guest { guest | feedback = feedback } } , cmds_ ) + + Guest.UpdatedShared newShared -> + ( { m | session = Page.Guest { guest | shared = newShared } } + , cmds_ + ) ) ( { model | status = toStatus uResult.model } , [] diff --git a/src/elm/Page/Login.elm b/src/elm/Page/Login.elm index e6313478b..0554f2f19 100755 --- a/src/elm/Page/Login.elm +++ b/src/elm/Page/Login.elm @@ -63,8 +63,8 @@ initPassphraseModel = } -initPinModel : String -> PinModel -initPinModel passphrase = +initPinModel : Bool -> String -> PinModel +initPinModel pinVisibility passphrase = { isSigningIn = False , passphrase = passphrase , pinModel = @@ -74,6 +74,7 @@ initPinModel passphrase = , withConfirmation = True , submitLabel = "auth.login.submit" , submittingLabel = "auth.login.submitting" + , pinVisibility = pinVisibility } } @@ -349,7 +350,7 @@ update msg model guest = ( WentToPin validPassphrase, EnteringPassphrase _ ) -> Validate.fromValid validPassphrase |> .passphrase - |> initPinModel + |> initPinModel guest.shared.pinVisibility |> EnteringPin |> UR.init |> UR.addCmd @@ -608,10 +609,14 @@ updateWithPin msg model ({ shared } as guest) = let ( pinModel, submitStatus ) = Pin.update subMsg model.pinModel + + ( newShared, submitCmd ) = + Pin.postSubmitAction pinModel submitStatus shared SubmittedPinWithSuccess in { model | pinModel = pinModel } |> UR.init - |> UR.addCmd (Pin.maybeSubmitCmd submitStatus SubmittedPinWithSuccess) + |> UR.addCmd submitCmd + |> UR.addExt (PinGuestExternal (Guest.UpdatedShared newShared)) diff --git a/src/elm/Page/Profile.elm b/src/elm/Page/Profile.elm index dfb806de7..3723a7a16 100755 --- a/src/elm/Page/Profile.elm +++ b/src/elm/Page/Profile.elm @@ -111,6 +111,7 @@ init loggedIn profileName = , withConfirmation = False , submitLabel = "profile.pin.button" , submittingLabel = "profile.pin.button" + , pinVisibility = loggedIn.shared.pinVisibility } , currentPin = Nothing } @@ -474,7 +475,14 @@ update msg model loggedIn = |> UR.init ClickedChangePin -> - { model | isNewPinModalVisible = True } + let + oldPinInputModel = + model.pinInputModel + in + { model + | isNewPinModalVisible = True + , pinInputModel = { oldPinInputModel | isPinVisible = loggedIn.auth.pinModel.isPinVisible } + } |> UR.init |> LoggedIn.withAuthentication loggedIn model @@ -488,10 +496,14 @@ update msg model loggedIn = let ( newPinModel, submitStatus ) = Pin.update subMsg model.pinInputModel + + ( newShared, submitCmd ) = + Pin.postSubmitAction newPinModel submitStatus loggedIn.shared SubmittedNewPin in { model | pinInputModel = newPinModel } |> UR.init - |> UR.addCmd (Pin.maybeSubmitCmd submitStatus SubmittedNewPin) + |> UR.addCmd submitCmd + |> UR.addExt (LoggedIn.UpdatedLoggedIn { loggedIn | shared = newShared }) SubmittedNewPin newPin -> let diff --git a/src/elm/Ports.elm b/src/elm/Ports.elm index 888d01272..6653cf404 100755 --- a/src/elm/Ports.elm +++ b/src/elm/Ports.elm @@ -12,6 +12,7 @@ port module Ports exposing , setMarkdownContent , storeAuthToken , storeLanguage + , storePinVisibility , storeRecentSearches , storeSelectedCommunitySymbol ) @@ -69,12 +70,12 @@ port javascriptInPort : (Value -> msg) -> Sub msg port storeLanguage : String -> Cmd msg -{-| Store recent searches to the `localStorage`. +{-| Store recent searches -} port storeRecentSearches : String -> Cmd msg -{-| Ping JS to send back the recent searches from the `localStorage`. +{-| Ping JS to send back the recent searches -} port getRecentSearches : () -> Cmd msg @@ -90,6 +91,11 @@ port storeAuthToken : String -> Cmd msg port storeSelectedCommunitySymbol : String -> Cmd msg +{-| Store whether to show or hide the pin by default +-} +port storePinVisibility : Bool -> Cmd msg + + {-| Send info about a link in a MarkdownEditor to be treated on JS -} sendMarkdownLink : { id : String, label : String, url : String } -> Cmd msg diff --git a/src/elm/Session/Guest.elm b/src/elm/Session/Guest.elm index 7be52c1a3..3569edad3 100755 --- a/src/elm/Session/Guest.elm +++ b/src/elm/Session/Guest.elm @@ -318,6 +318,7 @@ viewPageHeader model shared = type External = LoggedIn Eos.PrivateKey Auth.SignInResponse | SetFeedback Feedback.Model + | UpdatedShared Shared type BroadcastMsg diff --git a/src/elm/Session/LoggedIn.elm b/src/elm/Session/LoggedIn.elm index 752a85aa4..69e7ec1d4 100755 --- a/src/elm/Session/LoggedIn.elm +++ b/src/elm/Session/LoggedIn.elm @@ -183,7 +183,7 @@ initModel shared maybePrivateKey_ accountName authToken = , notification = Notification.init , unreadCount = 0 , showAuthModal = False - , auth = Auth.init maybePrivateKey_ + , auth = Auth.init shared.pinVisibility maybePrivateKey_ , feedback = Feedback.Hidden , showCommunitySelector = False , searchModel = Search.init @@ -1191,6 +1191,10 @@ update msg model = , data = Dict.fromList [ ( "username", Eos.encodeName user.account ) ] , level = Log.Info } + + Auth.UpdatedShared newShared -> + uResult + |> UR.mapModel (\m -> { m | shared = newShared }) ) CompletedLoadUnread payload -> diff --git a/src/elm/Session/Shared.elm b/src/elm/Session/Shared.elm index dfb6b384b..c29d16fd1 100755 --- a/src/elm/Session/Shared.elm +++ b/src/elm/Session/Shared.elm @@ -52,6 +52,7 @@ type alias Shared = , canReadClipboard : Bool , useSubdomain : Bool , selectedCommunity : Maybe Eos.Symbol + , pinVisibility : Bool } @@ -91,6 +92,7 @@ init ({ maybeAccount, endpoints, allowCommunityCreation, tokenContract, communit , canReadClipboard = flags.canReadClipboard , useSubdomain = flags.useSubdomain , selectedCommunity = flags.selectedCommunity + , pinVisibility = flags.pinVisibility } , case environment of Production -> diff --git a/src/elm/View/Pin.elm b/src/elm/View/Pin.elm index 28f9ecb51..8d01ec045 100644 --- a/src/elm/View/Pin.elm +++ b/src/elm/View/Pin.elm @@ -5,8 +5,8 @@ module View.Pin exposing , RequiredOptions , SubmitStatus(..) , init - , maybeSubmitCmd , msgToString + , postSubmitAction , update , view , withAttrs @@ -25,7 +25,8 @@ import Html exposing (Html, button, div, text) import Html.Attributes exposing (attribute, autocomplete, class, classList, disabled, maxlength, required, type_) import Html.Events exposing (keyCode, onClick, preventDefaultOn) import Json.Decode as Decode -import Session.Shared exposing (Translators) +import Ports +import Session.Shared exposing (Shared, Translators) import Task import Validate import View.Form.Input @@ -70,13 +71,14 @@ type alias RequiredOptions = , withConfirmation : Bool , submitLabel : String , submittingLabel : String + , pinVisibility : Bool } {-| Initializes a `Model` with some initial `RequiredOptions` -} init : RequiredOptions -> Model -init { label, id, withConfirmation, submitLabel, submittingLabel } = +init { label, id, withConfirmation, submitLabel, submittingLabel, pinVisibility } = { label = label , disabled = False , id = id @@ -89,8 +91,8 @@ init { label, id, withConfirmation, submitLabel, submittingLabel } = Nothing , placeholder = String.repeat pinLength "*" , problems = [] - , isPinVisible = True - , isPinConfirmationVisible = True + , isPinVisible = pinVisibility + , isPinConfirmationVisible = pinVisibility , isSubmitting = False , submitLabel = submitLabel , submittingLabel = submittingLabel @@ -306,18 +308,23 @@ update msg model = -- UTILS -maybeSubmitCmd : SubmitStatus -> (String -> msg) -> Cmd msg -maybeSubmitCmd status toMsg = +postSubmitAction : Model -> SubmitStatus -> Shared -> (String -> msg) -> ( Shared, Cmd msg ) +postSubmitAction model status shared toMsg = case status of NotAsked -> - Cmd.none + ( shared, Cmd.none ) WithError -> - Cmd.none + ( shared, Cmd.none ) Success pin -> - Task.succeed pin - |> Task.perform toMsg + ( { shared | pinVisibility = model.isPinVisible } + , Cmd.batch + [ Task.succeed pin + |> Task.perform toMsg + , Ports.storePinVisibility model.isPinVisible + ] + ) withDisabled : Bool -> Model -> Model diff --git a/src/index.js b/src/index.js index 10572facb..753b772d5 100755 --- a/src/index.js +++ b/src/index.js @@ -503,6 +503,7 @@ const PUSH_PREF = 'bespiral.push.pref' const AUTH_TOKEN = 'bespiral.auth_token' const RECENT_SEARCHES = 'bespiral.recent_search' const SELECTED_COMMUNITY_KEY = 'bespiral.selected_community' +const PIN_VISIBILITY_KEY = 'bespiral.pin_visibility' const env = process.env.NODE_ENV || 'development' const graphqlSecret = process.env.GRAPHQL_SECRET || '' const useSubdomain = process.env.USE_SUBDOMAIN === undefined ? true : process.env.USE_SUBDOMAIN !== 'false' @@ -641,32 +642,42 @@ const cookieKey = (key) => { } const getItem = (key) => { - const result = document.cookie.match('(^|[^;]+)\\s*' + cookieKey(key) + '\\s*=\\s*([^;]+)') - return result ? result.pop() : null + if (useSubdomain) { + const result = document.cookie.match('(^|[^;]+)\\s*' + cookieKey(key) + '\\s*=\\s*([^;]+)') + return result ? result.pop() : null + } + + return window.localStorage.getItem(cookieKey(key)) || null } const removeItem = (key) => { document.cookie = `${cookieKey(key)}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; ${cookieDomain()}; path=/; SameSite=Strict; Secure` - window.localStorage.removeItem(key) + window.localStorage.removeItem(cookieKey(key)) } const setItem = (key, value) => { - // This is the maximum possible expiration date for some browsers, because - // they use 32 bits to represent this field (maxExpirationDate === 2^31 - 1). - // This is equivalent to the date 2038-01-19 04:14:07 - const maxExpirationDate = 2147483647 - document.cookie = `${cookieKey(key)}=${value}; expires=${new Date(maxExpirationDate * 1000).toUTCString()}; ${cookieDomain()}; path=/; SameSite=Strict; Secure` + if (useSubdomain) { + // This is the maximum possible expiration date for some browsers, because + // they use 32 bits to represent this field (maxExpirationDate === 2^31 - 1). + // This is equivalent to the date 2038-01-19 04:14:07 + const maxExpirationDate = 2147483647 + document.cookie = `${cookieKey(key)}=${value}; expires=${new Date(maxExpirationDate * 1000).toUTCString()}; ${cookieDomain()}; path=/; SameSite=Strict; Secure` + } else { + window.localStorage.setItem(cookieKey(key), value) + } } const storedKeys = [USER_KEY, LANGUAGE_KEY, PUSH_PREF, AUTH_TOKEN, RECENT_SEARCHES, SELECTED_COMMUNITY_KEY] -storedKeys.forEach((key) => { - const localStorageValue = window.localStorage.getItem(key) - if (localStorageValue !== null) { - setItem(key, localStorageValue) - window.localStorage.removeItem(key) - } -}) +if (useSubdomain) { + storedKeys.forEach((key) => { + const localStorageValue = window.localStorage.getItem(key) + if (localStorageValue !== null) { + setItem(key, localStorageValue) + window.localStorage.removeItem(key) + } + }) +} pdfMake.vfs = pdfFonts.pdfMake.vfs pdfMake.fonts = { @@ -769,7 +780,8 @@ function flags () { communityContract: config.communityContract, canReadClipboard: canReadClipboard(), useSubdomain: useSubdomain, - selectedCommunity: getItem(SELECTED_COMMUNITY_KEY) + selectedCommunity: getItem(SELECTED_COMMUNITY_KEY), + pinVisibility: JSON.parse(getItem(PIN_VISIBILITY_KEY)) || false } } @@ -868,6 +880,18 @@ app.ports.storeSelectedCommunitySymbol.subscribe(symbol => { }) }) +app.ports.storePinVisibility.subscribe(pinVisibility => { + setItem(PIN_VISIBILITY_KEY, pinVisibility) + addBreadcrumb({ + type: 'info', + category: 'storePinVisibility', + message: 'Stored pin visibility', + data: { pinVisibility }, + localData: {}, + level: 'debug' + }) +}) + app.ports.addPlausibleScriptPort.subscribe(({ domain, src }) => { const plausibleScript = document.createElement('script') plausibleScript.setAttribute('src', src)