From 3d2479a431cf6741ea05228bdb4e491a93c10724 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Thu, 23 Sep 2021 19:04:22 -0300 Subject: [PATCH 01/17] Update elm-community/list-extra --- elm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elm.json b/elm.json index 76a4b22ec..eb4ca4ecb 100755 --- a/elm.json +++ b/elm.json @@ -26,7 +26,7 @@ "elm/svg": "1.0.1", "elm/time": "1.0.0", "elm/url": "1.0.0", - "elm-community/list-extra": "8.2.4", + "elm-community/list-extra": "8.5.1", "elm-community/maybe-extra": "5.2.0", "elm-community/string-extra": "4.0.1", "jfmengels/elm-review": "2.3.2", From af8d34b88490905d30d736e79f53c8f5a55639dd Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Thu, 23 Sep 2021 19:05:23 -0300 Subject: [PATCH 02/17] Add structure to query multiple community fields --- src/elm/Community.elm | 75 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/src/elm/Community.elm b/src/elm/Community.elm index ae21056fa..578769a91 100755 --- a/src/elm/Community.elm +++ b/src/elm/Community.elm @@ -3,6 +3,8 @@ module Community exposing , CommunityPreview , CreateCommunityData , CreateCommunityDataInput + , Field(..) + , FieldValue(..) , Invite , Metadata , Model @@ -23,11 +25,16 @@ module Community exposing , isNonExistingCommunityError , logoBackground , newCommunitySubscription + , objectiveSelectionSet + , queryForField + , queryForFields + , setFieldValue , subdomainQuery , symbolQuery ) import Action exposing (Action) +import Api.Graphql import Cambiatus.Mutation as Mutation import Cambiatus.Object import Cambiatus.Object.Community as Community @@ -52,7 +59,9 @@ import Html.Attributes exposing (class, classList, src) import Json.Decode as Decode exposing (Decoder) import Json.Decode.Pipeline exposing (required) import Json.Encode as Encode exposing (Value) +import List.Extra import Profile +import RemoteData exposing (RemoteData) import Session.Shared exposing (Shared) import Time exposing (Posix) import Utils @@ -95,7 +104,9 @@ type alias Model = , productCount : Int , orderCount : Int , members : List Profile.Minimal - , objectives : List Objective + + -- TODO - Figure out a type for this + , objectives : RemoteData () (List Objective) , hasObjectives : Bool , hasShop : Bool , hasKyc : Bool @@ -106,6 +117,21 @@ type alias Model = } +type Field + = ObjectivesField + + +type FieldValue + = ObjectivesValue (List Objective) + + +setFieldValue : FieldValue -> Model -> Model +setFieldValue fieldValue model = + case fieldValue of + ObjectivesValue objectives -> + { model | objectives = RemoteData.Success objectives } + + -- GraphQL @@ -141,7 +167,7 @@ communitySelectionSet = |> with Community.productCount |> with Community.orderCount |> with (Community.members Profile.minimalSelectionSet) - |> with (Community.objectives objectiveSelectionSet) + |> SelectionSet.hardcoded RemoteData.NotAsked |> with Community.hasObjectives |> with Community.hasShop |> with Community.hasKyc @@ -175,6 +201,51 @@ newCommunitySubscription symbol = Subscription.newcommunity args selectionSet +selectionSetForField : Field -> SelectionSet FieldValue Cambiatus.Object.Community +selectionSetForField field = + case field of + ObjectivesField -> + Community.objectives objectiveSelectionSet + |> SelectionSet.map ObjectivesValue + + +queryForField : + Eos.Symbol + -> Shared + -> String + -> Field + -> (RemoteData (Graphql.Http.Error (Maybe FieldValue)) (Maybe FieldValue) -> msg) + -> Cmd msg +queryForField symbol shared authToken field toMsg = + Api.Graphql.query shared + (Just authToken) + (field + |> selectionSetForField + |> Query.community (\optionals -> { optionals | symbol = Present <| Eos.symbolToString symbol }) + ) + toMsg + + +queryForFields : + Eos.Symbol + -> Shared + -> String + -> List Field + -> (RemoteData (Graphql.Http.Error (List FieldValue)) (List FieldValue) -> msg) + -> Cmd msg +queryForFields symbol shared authToken fields toMsg = + Api.Graphql.query shared + (Just authToken) + (fields + |> List.Extra.unique + |> List.map selectionSetForField + |> SelectionSet.list + |> Query.community (\optionals -> { optionals | symbol = Present <| Eos.symbolToString symbol }) + |> SelectionSet.withDefault [] + ) + toMsg + + symbolQuery : Eos.Symbol -> SelectionSet (Maybe Model) RootQuery symbolQuery symbol = Query.community (\optionals -> { optionals | symbol = Present <| Eos.symbolToString symbol }) communitySelectionSet From 0b5f92bd3602b0bdeb09077a346d455c6b30ea22 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Thu, 23 Sep 2021 19:10:13 -0300 Subject: [PATCH 03/17] Create initial structure and validate it on Community page --- src/elm/Main.elm | 3 +- src/elm/Page/Community.elm | 31 +++-- src/elm/Page/Community/ActionEditor.elm | 21 +-- src/elm/Page/Community/ObjectiveEditor.elm | 49 ++++--- src/elm/Page/Community/Objectives.elm | 64 +++++---- src/elm/Session/LoggedIn.elm | 155 ++++++++++++++++++++- 6 files changed, 246 insertions(+), 77 deletions(-) diff --git a/src/elm/Main.elm b/src/elm/Main.elm index 95744ed95..96f3288f0 100755 --- a/src/elm/Main.elm +++ b/src/elm/Main.elm @@ -823,8 +823,7 @@ updateLoggedInUResult toStatus toMsg model uResult = ) updateResult.afterAuthMsg } - , Cmd.map toMsg updateResult.externalCmd - :: Cmd.map (Page.GotLoggedInMsg >> GotPageMsg) updateResult.cmd + , Cmd.map (Page.GotLoggedInMsg >> GotPageMsg) updateResult.cmd :: broadcastCmd :: cmds_ ) diff --git a/src/elm/Page/Community.elm b/src/elm/Page/Community.elm index 9a8972f12..e8955d25c 100755 --- a/src/elm/Page/Community.elm +++ b/src/elm/Page/Community.elm @@ -39,7 +39,7 @@ import View.MarkdownEditor init : LoggedIn.Model -> ( Model, Cmd Msg ) init loggedIn = ( initModel loggedIn - , Task.succeed RequestedReloadCommunity |> Task.perform identity + , Task.succeed RequestedCommunityObjectives |> Task.perform identity ) @@ -113,13 +113,18 @@ view loggedIn model = ] , div [ class "container mx-auto" ] [ if community.hasObjectives then - div [ class "px-4 pb-4" ] - [ div [ class "container bg-white py-6 sm:py-8 px-3 sm:px-6 rounded-lg mt-4" ] - (Page.viewTitle (t "community.objectives.title_plural") - :: List.indexedMap (viewObjective loggedIn model community) - community.objectives - ) - ] + case community.objectives of + RemoteData.Success objectives -> + div [ class "px-4 pb-4" ] + [ div [ class "container bg-white py-6 sm:py-8 px-3 sm:px-6 rounded-lg mt-4" ] + (Page.viewTitle (t "community.objectives.title_plural") + :: List.indexedMap (viewObjective loggedIn model community) + objectives + ) + ] + + _ -> + text "" else text "" @@ -146,7 +151,7 @@ viewCommunityStats { t, tr } community model = RemoteData.isSuccess model.tokenInfo in div - [ class "container mx-auto px-4 mb-5 grid grid-cols-2 grid-rows-6 gap-4 grid-flow-row-dense md:grid-cols-4 md:grid-rows-3 md:mb-10" + [ class "container mx-auto mt-4 px-4 mb-5 grid grid-cols-2 grid-rows-6 gap-4 grid-flow-row-dense md:grid-cols-4 md:grid-rows-3 md:mb-10" , classList [ ( "grid-rows-4", not hasTokenInfo ) ] ] [ case model.tokenInfo of @@ -327,7 +332,7 @@ type alias UpdateResult = type Msg = NoOp - | RequestedReloadCommunity + | RequestedCommunityObjectives | CompletedLoadCommunity Community.Model | GotTokenInfo (Result Http.Error Token.Model) -- Objective @@ -342,9 +347,9 @@ update msg model loggedIn = NoOp -> UR.init model - RequestedReloadCommunity -> + RequestedCommunityObjectives -> UR.init model - |> UR.addExt (LoggedIn.ReloadResource LoggedIn.CommunityResource) + |> UR.addExt (LoggedIn.RequestedCommunityField Community.ObjectivesField) CompletedLoadCommunity community -> UR.init model @@ -397,7 +402,7 @@ msgToString msg = NoOp -> [ "NoOp" ] - RequestedReloadCommunity -> + RequestedCommunityObjectives -> [ "RequestedReloadCommunity" ] CompletedLoadCommunity _ -> diff --git a/src/elm/Page/Community/ActionEditor.elm b/src/elm/Page/Community/ActionEditor.elm index 2caf3ad83..35f4ccbd7 100755 --- a/src/elm/Page/Community/ActionEditor.elm +++ b/src/elm/Page/Community/ActionEditor.elm @@ -564,16 +564,17 @@ update msg model ({ shared } as loggedIn) = -- Check the action belongs to the objective let maybeObjective = - List.filterMap - (\o -> - if o.id == model.objectiveId then - Just o - - else - Nothing - ) - community.objectives - |> List.head + -- List.filterMap + -- (\o -> + -- if o.id == model.objectiveId then + -- Just o + -- else + -- Nothing + -- ) + -- community.objectives + -- |> List.head + -- TODO + Nothing in case ( maybeObjective, model.actionId ) of ( Just objective, Just actionId ) -> diff --git a/src/elm/Page/Community/ObjectiveEditor.elm b/src/elm/Page/Community/ObjectiveEditor.elm index c535584a7..260701064 100644 --- a/src/elm/Page/Community/ObjectiveEditor.elm +++ b/src/elm/Page/Community/ObjectiveEditor.elm @@ -112,6 +112,7 @@ type alias UpdateResult = type Msg = CompletedLoadCommunity Community.Model + | CompletedLoadObjectives (List Community.Objective) | ClosedAuthModal | GotDescriptionEditorMsg MarkdownEditor.Msg | ClickedSaveObjective @@ -394,24 +395,26 @@ update msg model loggedIn = if model.status == Loading then case model.objectiveId of Just objectiveId -> - case List.find (\o -> o.id == objectiveId) community.objectives of - Just objective -> - { model - | status = - Editing - |> EditingObjective objective - { description = - MarkdownEditor.init "objective-description" - |> MarkdownEditor.setContents objective.description - , isCompleted = objective.isCompleted - } - |> Authorized - } - |> UR.init - - Nothing -> - { model | status = NotFound } - |> UR.init + -- case List.find (\o -> o.id == objectiveId) community.objectives of + -- Just objective -> + -- { model + -- | status = + -- Editing + -- |> EditingObjective objective + -- { description = + -- MarkdownEditor.init "objective-description" + -- |> MarkdownEditor.setContents objective.description + -- , isCompleted = objective.isCompleted + -- } + -- |> Authorized + -- } + -- |> UR.init + -- Nothing -> + -- { model | status = NotFound } + -- |> UR.init + -- TODO + model + |> UR.init Nothing -> { model @@ -429,6 +432,11 @@ update msg model loggedIn = { model | status = Unauthorized } |> UR.init + CompletedLoadObjectives objectives -> + -- TODO + model + |> UR.init + ClosedAuthModal -> case model.status of Authorized (CreatingObjective form SavingCreation) -> @@ -688,8 +696,6 @@ update msg model loggedIn = , level = Log.Warning } - -- ======= - -- >>>>>>> master _ -> model |> UR.init @@ -939,6 +945,9 @@ msgToString msg = CompletedLoadCommunity _ -> [ "CompletedLoadCommunity" ] + CompletedLoadObjectives _ -> + [ "CompletedLoadObjectives" ] + ClosedAuthModal -> [ "ClosedAuthModal" ] diff --git a/src/elm/Page/Community/Objectives.elm b/src/elm/Page/Community/Objectives.elm index 3c958367f..fc481708c 100644 --- a/src/elm/Page/Community/Objectives.elm +++ b/src/elm/Page/Community/Objectives.elm @@ -81,10 +81,12 @@ view ({ shared } as loggedIn) model = , div [ class "container mx-auto px-4 my-10" ] [ div [ class "flex justify-end mb-10" ] [ viewNewObjectiveButton loggedIn community ] , div [] - (community.objectives + -- (community.objectives + -- TODO + ([] |> List.sortBy .id |> List.reverse - |> List.indexedMap (viewObjective loggedIn model community) + |> List.indexedMap (viewObjective loggedIn model) ) ] ] @@ -126,8 +128,8 @@ viewNewObjectiveButton ({ shared } as loggedIn) community = text "" -viewObjective : LoggedIn.Model -> Model -> Community.Model -> Int -> Community.Objective -> Html Msg -viewObjective ({ shared } as loggedIn) model _ index objective = +viewObjective : LoggedIn.Model -> Model -> Int -> Community.Objective -> Html Msg +viewObjective ({ shared } as loggedIn) model index objective = let isOpen : Bool isOpen = @@ -409,32 +411,34 @@ update msg model loggedIn = } else - { model - | openObjective = Just index - , profileSummaries = - loggedIn.selectedCommunity - |> RemoteData.toMaybe - |> Maybe.map .objectives - |> Maybe.andThen (List.getAt index) - |> Maybe.map .actions - |> Maybe.withDefault [] - |> List.map - (\action -> - ( action.id - , List.length action.validators - |> Profile.Summary.initMany False - ) - ) - |> Dict.fromList - } - |> UR.init - |> UR.addBreadcrumb - { type_ = Log.DebugBreadcrumb - , category = msg - , message = "Closed objective" - , data = Dict.fromList [ ( "objectiveId", Encode.int index ) ] - , level = Log.DebugLevel - } + -- { model + -- | openObjective = Just index + -- , profileSummaries = + -- loggedIn.selectedCommunity + -- |> RemoteData.toMaybe + -- |> Maybe.map .objectives + -- |> Maybe.andThen (List.getAt index) + -- |> Maybe.map .actions + -- |> Maybe.withDefault [] + -- |> List.map + -- (\action -> + -- ( action.id + -- , List.length action.validators + -- |> Profile.Summary.initMany False + -- ) + -- ) + -- |> Dict.fromList + -- } + -- |> UR.init + -- |> UR.addBreadcrumb + -- { type_ = Log.DebugBreadcrumb + -- , category = msg + -- , message = "Closed objective" + -- , data = Dict.fromList [ ( "objectiveId", Encode.int index ) ] + -- , level = Log.DebugLevel + -- } + -- TODO + UR.init model GotProfileSummaryMsg actionIndex validatorIndex subMsg -> { model diff --git a/src/elm/Session/LoggedIn.elm b/src/elm/Session/LoggedIn.elm index 5d09c72cb..dcf4a6d4e 100755 --- a/src/elm/Session/LoggedIn.elm +++ b/src/elm/Session/LoggedIn.elm @@ -28,7 +28,9 @@ import Api.Graphql import Auth import Avatar import Cambiatus.Object +import Cambiatus.Object.Community import Cambiatus.Object.UnreadNotifications +import Cambiatus.Query import Cambiatus.Subscription as Subscription import Community import Dict @@ -37,6 +39,7 @@ import Eos.Account as Eos import Graphql.Document import Graphql.Http import Graphql.Operation exposing (RootSubscription) +import Graphql.OptionalArgument exposing (OptionalArgument(..)) import Graphql.SelectionSet exposing (SelectionSet) import Html exposing (Html, a, button, div, footer, img, li, nav, p, text, ul) import Html.Attributes exposing (class, classList, src, type_) @@ -167,6 +170,7 @@ type alias Model = , searchModel : Search.Model , claimingAction : Action.Model , authToken : String + , queuedCommunityFields : List Community.Field } @@ -190,6 +194,7 @@ initModel shared maybePrivateKey_ accountName authToken = , searchModel = Search.init , claimingAction = { status = Action.NotAsked, feedback = Nothing, needsPinConfirmation = False } , authToken = authToken + , queuedCommunityFields = [] } @@ -738,6 +743,7 @@ type External msg | CreatedCommunity Eos.Symbol String | ExternalBroadcast BroadcastMsg | ReloadResource Resource + | RequestedCommunityField Community.Field | RequiredAuthentication { successMsg : msg, errorMsg : msg } | ShowFeedback Feedback.Status String | HideFeedback @@ -761,6 +767,9 @@ mapExternal mapFn msg = ReloadResource resource -> ReloadResource resource + RequestedCommunityField field -> + RequestedCommunityField field + RequiredAuthentication { successMsg, errorMsg } -> RequiredAuthentication { successMsg = mapFn successMsg, errorMsg = mapFn errorMsg } @@ -783,7 +792,6 @@ updateExternal : -> { model : Model , cmd : Cmd Msg - , externalCmd : Cmd msg , broadcastMsg : Maybe BroadcastMsg , afterAuthMsg : Maybe { successMsg : msg, errorMsg : msg } } @@ -792,7 +800,6 @@ updateExternal externalMsg ({ shared } as model) = defaultResult = { model = model , cmd = Cmd.none - , externalCmd = Cmd.none , broadcastMsg = Nothing , afterAuthMsg = Nothing } @@ -836,6 +843,17 @@ updateExternal externalMsg ({ shared } as model) = in { defaultResult | model = newModel, cmd = cmd, broadcastMsg = Just broadcastMsg } + CommunityFieldLoaded community field -> + { defaultResult + | model = + { model + | selectedCommunity = + Community.setFieldValue field community + |> RemoteData.Success + } + , broadcastMsg = Just broadcastMsg + } + ProfileLoaded profile_ -> { defaultResult | model = { model | profile = RemoteData.Success profile_ } @@ -873,6 +891,50 @@ updateExternal externalMsg ({ shared } as model) = ReloadResource TimeResource -> { defaultResult | cmd = Task.perform GotTimeInternal Time.now } + RequestedCommunityField field -> + case model.selectedCommunity of + RemoteData.Success community -> + let + isFieldLoading = + case field of + Community.ObjectivesField -> + RemoteData.isLoading community.objectives + + maybeFieldValue = + case field of + Community.ObjectivesField -> + community.objectives + |> RemoteData.toMaybe + |> Maybe.map Community.ObjectivesValue + in + if isFieldLoading then + defaultResult + + else + case maybeFieldValue of + Nothing -> + -- TODO - Set field as loading + { defaultResult + | cmd = + Community.queryForField community.symbol + shared + model.authToken + field + (CompletedLoadCommunityField community) + } + + Just fieldValue -> + { defaultResult | broadcastMsg = Just (CommunityFieldLoaded community fieldValue) } + + _ -> + { defaultResult + | model = + { model + | queuedCommunityFields = + field :: model.queuedCommunityFields + } + } + RequiredAuthentication afterAuthMsg -> { defaultResult | model = askedAuthentication model @@ -900,6 +962,7 @@ type ExternalMsg type BroadcastMsg = CommunityLoaded Community.Model + | CommunityFieldLoaded Community.Model Community.FieldValue | ProfileLoaded Profile.Model | GotTime Time.Posix | TranslationsLoaded @@ -910,6 +973,8 @@ type Msg | ClickedTryAgainTranslation | CompletedLoadProfile (RemoteData (Graphql.Http.Error (Maybe Profile.Model)) (Maybe Profile.Model)) | CompletedLoadCommunity (RemoteData (Graphql.Http.Error (Maybe Community.Model)) (Maybe Community.Model)) + | CompletedLoadCommunityField Community.Model (RemoteData (Graphql.Http.Error (Maybe Community.FieldValue)) (Maybe Community.FieldValue)) + | CompletedLoadCommunityFields Community.Model (RemoteData (Graphql.Http.Error (List Community.FieldValue)) (List Community.FieldValue)) | ClickedTryAgainProfile Eos.Name | ClickedLogout | ShowUserNav Bool @@ -1068,6 +1133,14 @@ update msg model = |> UR.addCmd cmd |> UR.addCmd (Ports.getRecentSearches ()) |> UR.addExt (CommunityLoaded community |> Broadcast) + -- TODO - Set fields as loading + |> UR.addCmd + (Community.queryForFields community.symbol + newModel.shared + newModel.authToken + newModel.queuedCommunityFields + (CompletedLoadCommunityFields community) + ) |> UR.addBreadcrumb { type_ = Log.DefaultBreadcrumb , category = msg @@ -1109,6 +1182,78 @@ update msg model = CompletedLoadCommunity RemoteData.Loading -> UR.init { model | selectedCommunity = RemoteData.Loading } + CompletedLoadCommunityField community (RemoteData.Success (Just fieldValue)) -> + { model + | selectedCommunity = + Community.setFieldValue fieldValue community + |> RemoteData.Success + } + |> UR.init + |> UR.addExt + (CommunityFieldLoaded community fieldValue + |> Broadcast + ) + + CompletedLoadCommunityField community (RemoteData.Success Nothing) -> + model + |> UR.init + |> UR.logImpossible msg + "Tried loading community field, but got Nothing in return" + (Just model.accountName) + { moduleName = "Session.LoggedIn", function = "update" } + [ Log.contextFromCommunity (RemoteData.Success community) ] + + CompletedLoadCommunityField _ (RemoteData.Failure err) -> + model + |> UR.init + |> UR.logGraphqlError msg + (Just model.accountName) + "Got an error when loading community field" + { moduleName = "Session.LoggedIn", function = "update" } + [] + err + + CompletedLoadCommunityField _ RemoteData.NotAsked -> + UR.init model + + CompletedLoadCommunityField _ RemoteData.Loading -> + UR.init model + + CompletedLoadCommunityFields community (RemoteData.Success fieldValues) -> + let + newCommunity = + List.foldl Community.setFieldValue community fieldValues + + addBroadcasts uResult = + List.foldl + (\field -> + UR.addExt + (CommunityFieldLoaded community field + |> Broadcast + ) + ) + uResult + fieldValues + in + { model | selectedCommunity = RemoteData.Success newCommunity } + |> UR.init + |> addBroadcasts + + CompletedLoadCommunityFields _ (RemoteData.Failure err) -> + UR.init model + |> UR.logGraphqlError msg + (Just model.accountName) + "Got an error when loading multiple community fields" + { moduleName = "Session.LoggedIn", function = "update" } + [] + err + + CompletedLoadCommunityFields _ RemoteData.NotAsked -> + UR.init model + + CompletedLoadCommunityFields _ RemoteData.Loading -> + UR.init model + ClickedTryAgainProfile accountName -> UR.init { model | profile = RemoteData.Loading } |> UR.addCmd @@ -1592,6 +1737,12 @@ msgToString msg = CompletedLoadCommunity r -> [ "CompletedLoadCommunity", UR.remoteDataToString r ] + CompletedLoadCommunityField _ _ -> + [ "CompletedLoadCommunityField" ] + + CompletedLoadCommunityFields _ _ -> + [ "CompletedLoadCommunityFields" ] + ClickedTryAgainProfile _ -> [ "ClickedTryAgainProfile" ] From 2dbea6632b9d07100e08d357fbb02ca94a4fde91 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Fri, 24 Sep 2021 12:43:55 -0300 Subject: [PATCH 04/17] Make uploads a requestable field --- src/elm/Community.elm | 58 ++++++++++++++++++- src/elm/Page/Community.elm | 2 +- src/elm/Page/Community/ObjectiveEditor.elm | 47 ++++++++------- src/elm/Page/Community/Settings/Info.elm | 66 +++++++++++++++++----- src/elm/Page/Join.elm | 9 +-- src/elm/Session/LoggedIn.elm | 45 +++++++-------- 6 files changed, 160 insertions(+), 67 deletions(-) diff --git a/src/elm/Community.elm b/src/elm/Community.elm index 578769a91..256ef78ec 100755 --- a/src/elm/Community.elm +++ b/src/elm/Community.elm @@ -22,10 +22,12 @@ module Community exposing , encodeUpdateData , encodeUpdateObjectiveAction , inviteQuery + , isFieldLoading , isNonExistingCommunityError , logoBackground + , maybeFieldValue + , mergeFields , newCommunitySubscription - , objectiveSelectionSet , queryForField , queryForFields , setFieldValue @@ -112,17 +114,22 @@ type alias Model = , hasKyc : Bool , hasAutoInvite : Bool , validators : List Eos.Name - , uploads : List String + + -- , validators : RemoteData () (List Eos.Name) + -- , uploads : List String + , uploads : RemoteData () (List String) , website : Maybe String } type Field = ObjectivesField + | UploadsField type FieldValue = ObjectivesValue (List Objective) + | UploadsValue (List String) setFieldValue : FieldValue -> Model -> Model @@ -131,6 +138,46 @@ setFieldValue fieldValue model = ObjectivesValue objectives -> { model | objectives = RemoteData.Success objectives } + UploadsValue uploads -> + { model | uploads = RemoteData.Success uploads } + + +isFieldLoading : Field -> Model -> Bool +isFieldLoading field model = + case field of + ObjectivesField -> + RemoteData.isLoading model.objectives + + UploadsField -> + RemoteData.isLoading model.uploads + + +maybeFieldValue : Field -> Model -> Maybe FieldValue +maybeFieldValue field model = + case field of + ObjectivesField -> + model.objectives + |> RemoteData.toMaybe + |> Maybe.map ObjectivesValue + + UploadsField -> + model.uploads + |> RemoteData.toMaybe + |> Maybe.map UploadsValue + + +mergeFields : RemoteData x Model -> Model -> Model +mergeFields loadedCommunity newCommunity = + case loadedCommunity of + RemoteData.Success oldCommunity -> + { newCommunity + | objectives = oldCommunity.objectives + , uploads = oldCommunity.uploads + } + + _ -> + newCommunity + -- GraphQL @@ -173,7 +220,8 @@ communitySelectionSet = |> with Community.hasKyc |> with Community.autoInvite |> with (Community.validators (Eos.nameSelectionSet Profile.account)) - |> with (Community.uploads Upload.url) + -- |> with (Community.uploads Upload.url) + |> SelectionSet.hardcoded RemoteData.NotAsked |> with Community.website @@ -208,6 +256,10 @@ selectionSetForField field = Community.objectives objectiveSelectionSet |> SelectionSet.map ObjectivesValue + UploadsField -> + Community.uploads Upload.url + |> SelectionSet.map UploadsValue + queryForField : Eos.Symbol diff --git a/src/elm/Page/Community.elm b/src/elm/Page/Community.elm index e8955d25c..db7c73a48 100755 --- a/src/elm/Page/Community.elm +++ b/src/elm/Page/Community.elm @@ -403,7 +403,7 @@ msgToString msg = [ "NoOp" ] RequestedCommunityObjectives -> - [ "RequestedReloadCommunity" ] + [ "RequestedCommunityObjectives" ] CompletedLoadCommunity _ -> [ "CompletedLoadCommunity" ] diff --git a/src/elm/Page/Community/ObjectiveEditor.elm b/src/elm/Page/Community/ObjectiveEditor.elm index 260701064..b00b8fa15 100644 --- a/src/elm/Page/Community/ObjectiveEditor.elm +++ b/src/elm/Page/Community/ObjectiveEditor.elm @@ -395,26 +395,30 @@ update msg model loggedIn = if model.status == Loading then case model.objectiveId of Just objectiveId -> - -- case List.find (\o -> o.id == objectiveId) community.objectives of - -- Just objective -> - -- { model - -- | status = - -- Editing - -- |> EditingObjective objective - -- { description = - -- MarkdownEditor.init "objective-description" - -- |> MarkdownEditor.setContents objective.description - -- , isCompleted = objective.isCompleted - -- } - -- |> Authorized - -- } - -- |> UR.init - -- Nothing -> - -- { model | status = NotFound } - -- |> UR.init - -- TODO - model - |> UR.init + case community.objectives of + RemoteData.Success objectives -> + case List.find (\o -> o.id == objectiveId) objectives of + -- TODO - Request reload objectives + Just objective -> + { model + | status = + Editing + |> EditingObjective objective + { description = + MarkdownEditor.init "objective-description" + |> MarkdownEditor.setContents objective.description + , isCompleted = objective.isCompleted + } + |> Authorized + } + |> UR.init + + Nothing -> + { model | status = NotFound } + |> UR.init + + _ -> + model |> UR.init Nothing -> { model @@ -903,6 +907,9 @@ receiveBroadcast broadcastMsg = LoggedIn.CommunityLoaded community -> Just (CompletedLoadCommunity community) + LoggedIn.CommunityFieldLoaded _ (Community.ObjectivesValue objectives) -> + Just (CompletedLoadObjectives objectives) + _ -> Nothing diff --git a/src/elm/Page/Community/Settings/Info.elm b/src/elm/Page/Community/Settings/Info.elm index 2d490e5f3..a9a588b33 100644 --- a/src/elm/Page/Community/Settings/Info.elm +++ b/src/elm/Page/Community/Settings/Info.elm @@ -99,6 +99,7 @@ init loggedIn = type Msg = Ignored | CompletedLoadCommunity Community.Model + | CompletedLoadUploads (List String) | ClosedAuthModal | EnteredLogo (List File) | CompletedLogoUpload (Result Http.Error String) @@ -128,17 +129,32 @@ update msg model ({ shared } as loggedIn) = UR.init model CompletedLoadCommunity community -> + let + ( coverPhoto, maybeRequestUploads ) = + case community.uploads of + RemoteData.Success uploads -> + ( case List.head uploads of + Just photo -> + RemoteData.Success photo + + Nothing -> + RemoteData.NotAsked + , identity + ) + + RemoteData.Loading -> + ( RemoteData.Loading, identity ) + + _ -> + ( RemoteData.Loading + , UR.addExt (LoggedIn.RequestedCommunityField Community.UploadsField) + ) + in { model | logo = RemoteData.Success community.logo , nameInput = community.name , descriptionInput = MarkdownEditor.setContents community.description model.descriptionInput - , coverPhoto = - case List.head community.uploads of - Just photo -> - RemoteData.Success photo - - Nothing -> - RemoteData.NotAsked + , coverPhoto = coverPhoto , subdomainInput = community.subdomain |> String.split "." @@ -151,6 +167,19 @@ update msg model ({ shared } as loggedIn) = , websiteInput = Maybe.withDefault "" community.website } |> UR.init + |> maybeRequestUploads + + CompletedLoadUploads uploads -> + { model + | coverPhoto = + case List.head uploads of + Just photo -> + RemoteData.Success photo + + Nothing -> + RemoteData.NotAsked + } + |> UR.init ClosedAuthModal -> { model | isLoading = False } @@ -324,9 +353,12 @@ update msg model ({ shared } as loggedIn) = case ( isModelValid shared.translators (RemoteData.toMaybe loggedIn.selectedCommunity) model , loggedIn.selectedCommunity + , loggedIn.selectedCommunity + |> RemoteData.mapError (\_ -> ()) + |> RemoteData.andThen .uploads ) of - ( True, RemoteData.Success community ) -> + ( True, RemoteData.Success community, RemoteData.Success communityUploads ) -> let authorization = { actor = loggedIn.accountName @@ -339,7 +371,8 @@ update msg model ({ shared } as loggedIn) = } newUpload = - case ( model.coverPhoto, List.head community.uploads ) of + -- TODO - Check this `case of` + case ( model.coverPhoto, List.head communityUploads ) of ( RemoteData.Success url, Just firstUpload ) -> if url == firstUpload then Nothing @@ -408,7 +441,7 @@ update msg model ({ shared } as loggedIn) = (Just loggedIn.authToken) (Community.addPhotosMutation community.symbol - (url :: community.uploads) + (url :: communityUploads) ) (CompletedAddingCoverPhoto url) @@ -535,9 +568,10 @@ update msg model ({ shared } as loggedIn) = Route.Dashboard newUploads = - case model.coverPhoto of - RemoteData.Success coverPhoto -> - coverPhoto :: community.uploads + case ( community.uploads, model.coverPhoto ) of + -- TODO - Check this + ( RemoteData.Success uploads, RemoteData.Success coverPhoto ) -> + RemoteData.Success (coverPhoto :: uploads) _ -> community.uploads @@ -1136,6 +1170,9 @@ receiveBroadcast broadcastMsg = LoggedIn.CommunityLoaded community -> Just (CompletedLoadCommunity community) + LoggedIn.CommunityFieldLoaded _ (Community.UploadsValue uploads) -> + Just (CompletedLoadUploads uploads) + _ -> Nothing @@ -1169,6 +1206,9 @@ msgToString msg = CompletedLoadCommunity _ -> [ "CompletedLoadCommunity" ] + CompletedLoadUploads _ -> + [ "CompletedLoadUploads" ] + ClosedAuthModal -> [ "ClosedAuthModal" ] diff --git a/src/elm/Page/Join.elm b/src/elm/Page/Join.elm index dc2dc9e03..3d2f45c4b 100644 --- a/src/elm/Page/Join.elm +++ b/src/elm/Page/Join.elm @@ -296,10 +296,11 @@ viewAsLoggedIn : String -> LoggedIn.Model -> Model -> Html Msg viewAsLoggedIn title loggedIn model = case loggedIn.selectedCommunity of RemoteData.Success community -> - div [ class "flex-grow flex" ] - [ Community.communityPreviewImage True loggedIn.shared community - , view_ False loggedIn.shared community model - ] + -- div [ class "flex-grow flex" ] + -- [ Community.communityPreviewImage True loggedIn.shared community + -- , view_ False loggedIn.shared community model + -- ] + text "TODO" RemoteData.Failure err -> Page.fullPageGraphQLError title err diff --git a/src/elm/Session/LoggedIn.elm b/src/elm/Session/LoggedIn.elm index dcf4a6d4e..e1018eadf 100755 --- a/src/elm/Session/LoggedIn.elm +++ b/src/elm/Session/LoggedIn.elm @@ -28,9 +28,7 @@ import Api.Graphql import Auth import Avatar import Cambiatus.Object -import Cambiatus.Object.Community import Cambiatus.Object.UnreadNotifications -import Cambiatus.Query import Cambiatus.Subscription as Subscription import Community import Dict @@ -39,7 +37,6 @@ import Eos.Account as Eos import Graphql.Document import Graphql.Http import Graphql.Operation exposing (RootSubscription) -import Graphql.OptionalArgument exposing (OptionalArgument(..)) import Graphql.SelectionSet exposing (SelectionSet) import Html exposing (Html, a, button, div, footer, img, li, nav, p, text, ul) import Html.Attributes exposing (class, classList, src, type_) @@ -894,24 +891,11 @@ updateExternal externalMsg ({ shared } as model) = RequestedCommunityField field -> case model.selectedCommunity of RemoteData.Success community -> - let - isFieldLoading = - case field of - Community.ObjectivesField -> - RemoteData.isLoading community.objectives - - maybeFieldValue = - case field of - Community.ObjectivesField -> - community.objectives - |> RemoteData.toMaybe - |> Maybe.map Community.ObjectivesValue - in - if isFieldLoading then + if Community.isFieldLoading field community then defaultResult else - case maybeFieldValue of + case Community.maybeFieldValue field community of Nothing -> -- TODO - Set field as loading { defaultResult @@ -924,7 +908,11 @@ updateExternal externalMsg ({ shared } as model) = } Just fieldValue -> - { defaultResult | broadcastMsg = Just (CommunityFieldLoaded community fieldValue) } + { defaultResult + | broadcastMsg = + Just + (CommunityFieldLoaded community fieldValue) + } _ -> { defaultResult @@ -1127,7 +1115,12 @@ update msg model = CompletedLoadCommunity (RemoteData.Success (Just community)) -> let ( newModel, cmd ) = - setCommunity community model + setCommunity + (Community.mergeFields model.selectedCommunity community) + model + + newCommunity = + Community.mergeFields newModel.selectedCommunity community in UR.init newModel |> UR.addCmd cmd @@ -1139,7 +1132,7 @@ update msg model = newModel.shared newModel.authToken newModel.queuedCommunityFields - (CompletedLoadCommunityFields community) + (CompletedLoadCommunityFields newCommunity) ) |> UR.addBreadcrumb { type_ = Log.DefaultBreadcrumb @@ -1183,14 +1176,14 @@ update msg model = UR.init { model | selectedCommunity = RemoteData.Loading } CompletedLoadCommunityField community (RemoteData.Success (Just fieldValue)) -> - { model - | selectedCommunity = + let + newCommunity = Community.setFieldValue fieldValue community - |> RemoteData.Success - } + in + { model | selectedCommunity = RemoteData.Success newCommunity } |> UR.init |> UR.addExt - (CommunityFieldLoaded community fieldValue + (CommunityFieldLoaded newCommunity fieldValue |> Broadcast ) From 97f95e2820c9c4faf38f127903787f594e2fb426 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 10:40:01 -0300 Subject: [PATCH 05/17] Fix objectives and uploads signatures --- src/elm/Community.elm | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/elm/Community.elm b/src/elm/Community.elm index 256ef78ec..a9ee46de5 100755 --- a/src/elm/Community.elm +++ b/src/elm/Community.elm @@ -106,18 +106,13 @@ type alias Model = , productCount : Int , orderCount : Int , members : List Profile.Minimal - - -- TODO - Figure out a type for this - , objectives : RemoteData () (List Objective) + , objectives : RemoteData (Graphql.Http.Error (List Objective)) (List Objective) , hasObjectives : Bool , hasShop : Bool , hasKyc : Bool , hasAutoInvite : Bool , validators : List Eos.Name - - -- , validators : RemoteData () (List Eos.Name) - -- , uploads : List String - , uploads : RemoteData () (List String) + , uploads : RemoteData (Graphql.Http.Error (List String)) (List String) , website : Maybe String } From 5320e3c354d6d3559da6335421928990faaec4ac Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 10:59:49 -0300 Subject: [PATCH 06/17] Introduce FieldError --- src/elm/Community.elm | 22 ++++++++++++++++++++++ src/elm/Page/Community/Settings/Info.elm | 8 ++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/elm/Community.elm b/src/elm/Community.elm index a9ee46de5..fc0abb855 100755 --- a/src/elm/Community.elm +++ b/src/elm/Community.elm @@ -4,6 +4,7 @@ module Community exposing , CreateCommunityData , CreateCommunityDataInput , Field(..) + , FieldError(..) , FieldValue(..) , Invite , Metadata @@ -21,6 +22,7 @@ module Community exposing , encodeCreateObjectiveAction , encodeUpdateData , encodeUpdateObjectiveAction + , getField , inviteQuery , isFieldLoading , isNonExistingCommunityError @@ -127,6 +129,26 @@ type FieldValue | UploadsValue (List String) +type FieldError a + = CommunityError (Graphql.Http.Error (Maybe Model)) + | FieldError a + + +getField : + RemoteData (Graphql.Http.Error (Maybe Model)) Model + -> (Model -> RemoteData err field) + -> RemoteData (FieldError err) ( Model, field ) +getField remoteDataModel accessor = + remoteDataModel + |> RemoteData.mapError CommunityError + |> RemoteData.andThen + (\model -> + accessor model + |> RemoteData.map (\field -> ( model, field )) + |> RemoteData.mapError FieldError + ) + + setFieldValue : FieldValue -> Model -> Model setFieldValue fieldValue model = case fieldValue of diff --git a/src/elm/Page/Community/Settings/Info.elm b/src/elm/Page/Community/Settings/Info.elm index a9a588b33..44d30be4c 100644 --- a/src/elm/Page/Community/Settings/Info.elm +++ b/src/elm/Page/Community/Settings/Info.elm @@ -352,13 +352,10 @@ update msg model ({ shared } as loggedIn) = GotDomainAvailableResponse (RemoteData.Success True) -> case ( isModelValid shared.translators (RemoteData.toMaybe loggedIn.selectedCommunity) model - , loggedIn.selectedCommunity - , loggedIn.selectedCommunity - |> RemoteData.mapError (\_ -> ()) - |> RemoteData.andThen .uploads + , Community.getField loggedIn.selectedCommunity .uploads ) of - ( True, RemoteData.Success community, RemoteData.Success communityUploads ) -> + ( True, RemoteData.Success ( community, communityUploads ) ) -> let authorization = { actor = loggedIn.accountName @@ -371,7 +368,6 @@ update msg model ({ shared } as loggedIn) = } newUpload = - -- TODO - Check this `case of` case ( model.coverPhoto, List.head communityUploads ) of ( RemoteData.Success url, Just firstUpload ) -> if url == firstUpload then From c5704dd3c32476d156d24164777720e53e833259 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 11:00:20 -0300 Subject: [PATCH 07/17] Refactor Objectives page to reload only objectives field and use new structure --- src/elm/Page/Community/Objectives.elm | 108 ++++++++++++-------------- src/elm/Session/LoggedIn.elm | 25 ++++++ 2 files changed, 74 insertions(+), 59 deletions(-) diff --git a/src/elm/Page/Community/Objectives.elm b/src/elm/Page/Community/Objectives.elm index fc481708c..6a4daaeef 100644 --- a/src/elm/Page/Community/Objectives.elm +++ b/src/elm/Page/Community/Objectives.elm @@ -17,7 +17,6 @@ import Profile.Summary import RemoteData import Route import Session.LoggedIn as LoggedIn exposing (External(..)) -import Task import Time exposing (Posix) import UpdateResult as UR import Utils @@ -28,10 +27,7 @@ import View.MarkdownEditor init : LoggedIn.Model -> ( Model, Cmd Msg ) init loggedIn = ( initModel - , Cmd.batch - [ Task.succeed RequestedReloadCommunity |> Task.perform identity - , LoggedIn.maybeInitWith CompletedLoadCommunity .selectedCommunity loggedIn - ] + , LoggedIn.maybeInitWith CompletedLoadCommunity .selectedCommunity loggedIn ) @@ -74,16 +70,18 @@ view ({ shared } as loggedIn) model = t "community.objectives.title_plural" content = - case ( loggedIn.selectedCommunity, model.status ) of - ( RemoteData.Success community, Loaded ) -> + case + ( Community.getField loggedIn.selectedCommunity .objectives + , model.status + ) + of + ( RemoteData.Success ( community, objectives ), Loaded ) -> div [] [ Page.viewHeader loggedIn (t "community.objectives.title_plural") , div [ class "container mx-auto px-4 my-10" ] [ div [ class "flex justify-end mb-10" ] [ viewNewObjectiveButton loggedIn community ] , div [] - -- (community.objectives - -- TODO - ([] + (objectives |> List.sortBy .id |> List.reverse |> List.indexedMap (viewObjective loggedIn model) @@ -98,7 +96,10 @@ view ({ shared } as loggedIn) model = [ text (shared.translators.t "community.edit.unauthorized") ] ] - ( RemoteData.Failure e, _ ) -> + ( RemoteData.Failure (Community.CommunityError e), _ ) -> + Page.fullPageGraphQLError (t "community.objectives.title_plural") e + + ( RemoteData.Failure (Community.FieldError e), _ ) -> Page.fullPageGraphQLError (t "community.objectives.title_plural") e ( RemoteData.Loading, _ ) -> @@ -372,7 +373,6 @@ type alias UpdateResult = type Msg = CompletedLoadCommunity Community.Model - | RequestedReloadCommunity | OpenObjective Int | GotProfileSummaryMsg Int Int Profile.Summary.Msg @@ -381,22 +381,17 @@ update : Msg -> Model -> LoggedIn.Model -> UpdateResult update msg model loggedIn = case msg of CompletedLoadCommunity community -> - UR.init - { model - | status = - if not community.hasObjectives then - Unauthorized - - else if community.creator == loggedIn.accountName then - Loaded - - else - Unauthorized - } - - RequestedReloadCommunity -> - UR.init model - |> UR.addExt (LoggedIn.ReloadResource LoggedIn.CommunityResource) + let + ( status, maybeRequestObjectives ) = + if community.hasObjectives && community.creator == loggedIn.accountName then + ( Loaded, UR.addExt (LoggedIn.RequestedReloadCommunityField Community.ObjectivesField) ) + + else + ( Unauthorized, identity ) + in + { model | status = status } + |> UR.init + |> maybeRequestObjectives OpenObjective index -> if model.openObjective == Just index then @@ -411,34 +406,32 @@ update msg model loggedIn = } else - -- { model - -- | openObjective = Just index - -- , profileSummaries = - -- loggedIn.selectedCommunity - -- |> RemoteData.toMaybe - -- |> Maybe.map .objectives - -- |> Maybe.andThen (List.getAt index) - -- |> Maybe.map .actions - -- |> Maybe.withDefault [] - -- |> List.map - -- (\action -> - -- ( action.id - -- , List.length action.validators - -- |> Profile.Summary.initMany False - -- ) - -- ) - -- |> Dict.fromList - -- } - -- |> UR.init - -- |> UR.addBreadcrumb - -- { type_ = Log.DebugBreadcrumb - -- , category = msg - -- , message = "Closed objective" - -- , data = Dict.fromList [ ( "objectiveId", Encode.int index ) ] - -- , level = Log.DebugLevel - -- } - -- TODO - UR.init model + { model + | openObjective = Just index + , profileSummaries = + loggedIn.selectedCommunity + |> RemoteData.toMaybe + |> Maybe.andThen (.objectives >> RemoteData.toMaybe) + |> Maybe.andThen (List.getAt index) + |> Maybe.map .actions + |> Maybe.withDefault [] + |> List.map + (\action -> + ( action.id + , List.length action.validators + |> Profile.Summary.initMany False + ) + ) + |> Dict.fromList + } + |> UR.init + |> UR.addBreadcrumb + { type_ = Log.DebugBreadcrumb + , category = msg + , message = "Closed objective" + , data = Dict.fromList [ ( "objectiveId", Encode.int index ) ] + , level = Log.DebugLevel + } GotProfileSummaryMsg actionIndex validatorIndex subMsg -> { model @@ -469,9 +462,6 @@ msgToString msg = CompletedLoadCommunity _ -> [ "CompletedLoadCommunity" ] - RequestedReloadCommunity -> - [ "RequestedReloadCommunity" ] - OpenObjective _ -> [ "OpenObjective" ] diff --git a/src/elm/Session/LoggedIn.elm b/src/elm/Session/LoggedIn.elm index e1018eadf..20917d792 100755 --- a/src/elm/Session/LoggedIn.elm +++ b/src/elm/Session/LoggedIn.elm @@ -740,6 +740,7 @@ type External msg | CreatedCommunity Eos.Symbol String | ExternalBroadcast BroadcastMsg | ReloadResource Resource + | RequestedReloadCommunityField Community.Field | RequestedCommunityField Community.Field | RequiredAuthentication { successMsg : msg, errorMsg : msg } | ShowFeedback Feedback.Status String @@ -767,6 +768,9 @@ mapExternal mapFn msg = RequestedCommunityField field -> RequestedCommunityField field + RequestedReloadCommunityField field -> + RequestedReloadCommunityField field + RequiredAuthentication { successMsg, errorMsg } -> RequiredAuthentication { successMsg = mapFn successMsg, errorMsg = mapFn errorMsg } @@ -923,6 +927,27 @@ updateExternal externalMsg ({ shared } as model) = } } + RequestedReloadCommunityField field -> + case model.selectedCommunity of + RemoteData.Success community -> + { defaultResult + | cmd = + Community.queryForField community.symbol + shared + model.authToken + field + (CompletedLoadCommunityField community) + } + + _ -> + { defaultResult + | model = + { model + | queuedCommunityFields = + field :: model.queuedCommunityFields + } + } + RequiredAuthentication afterAuthMsg -> { defaultResult | model = askedAuthentication model From 3a074872c4662abd31408446c009a2e65d739405 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 11:31:06 -0300 Subject: [PATCH 08/17] Reload objectives when entering community page, better visuals for objectives loading and error --- public/translations/amh-ETH.json | 1 + public/translations/cat-CAT.json | 1 + public/translations/en-US.json | 1 + public/translations/es-ES.json | 1 + public/translations/pt-BR.json | 1 + src/elm/Page/Community.elm | 51 ++++++++++++++++++++++---------- 6 files changed, 41 insertions(+), 15 deletions(-) diff --git a/public/translations/amh-ETH.json b/public/translations/amh-ETH.json index 6a25c5a4e..414b60cb4 100644 --- a/public/translations/amh-ETH.json +++ b/public/translations/amh-ETH.json @@ -471,6 +471,7 @@ "action_count": "{{actions}} ተግባራት", "complete": "ተጠናቅቋል", "edit": "አርትእ ዓላማዎችን", + "error_loading": "ግቦቹን ሲጭኑ አንድ የተሳሳተ ነገር ተከሰተ", "editor": { "not_found": "አልተገኘም", "error": "ዉይ የሆነ ችግር ተከስቷል!", diff --git a/public/translations/cat-CAT.json b/public/translations/cat-CAT.json index 7e15bd536..3cebe40ef 100755 --- a/public/translations/cat-CAT.json +++ b/public/translations/cat-CAT.json @@ -513,6 +513,7 @@ "action_count": "{{actions}} accions", "complete": "Completat", "edit": "Edita l'objectiu", + "error_loading": "S'ha produït un error en carregar els objectius", "editor": { "not_found": "No trobat", "error": "Ui! Quelcom ha fallat", diff --git a/public/translations/en-US.json b/public/translations/en-US.json index 038aa1efe..a3c80bf23 100755 --- a/public/translations/en-US.json +++ b/public/translations/en-US.json @@ -509,6 +509,7 @@ "action_count": "{{actions}} actions", "complete": "Complete", "edit": "Edit objective", + "error_loading": "Something went wrong when loading objectives", "editor": { "not_found": "Not Found", "error": "Ops something went wrong!", diff --git a/public/translations/es-ES.json b/public/translations/es-ES.json index ad09d711c..c804a02a6 100755 --- a/public/translations/es-ES.json +++ b/public/translations/es-ES.json @@ -513,6 +513,7 @@ "action_count": "{{actions}} acciones", "complete": "Terminado", "edit": "Editar objetivo", + "error_loading": "Ocurrió algo mal al cargar los objetivos", "editor": { "not_found": "No encontrado", "error": "¡Huy! Algo salió mal", diff --git a/public/translations/pt-BR.json b/public/translations/pt-BR.json index cb89216db..e0d5cb0f4 100755 --- a/public/translations/pt-BR.json +++ b/public/translations/pt-BR.json @@ -517,6 +517,7 @@ "action_count": "{{actions}} ações", "complete": "Completo", "edit": "Editar objetivo", + "error_loading": "Algo de errado aconteceu ao carregar os objetivos", "editor": { "not_found": "Não encontrado", "error": "Ops algo deu errado!", diff --git a/src/elm/Page/Community.elm b/src/elm/Page/Community.elm index db7c73a48..2b8a1c1fa 100755 --- a/src/elm/Page/Community.elm +++ b/src/elm/Page/Community.elm @@ -39,7 +39,7 @@ import View.MarkdownEditor init : LoggedIn.Model -> ( Model, Cmd Msg ) init loggedIn = ( initModel loggedIn - , Task.succeed RequestedCommunityObjectives |> Task.perform identity + , Task.succeed RequestedReloadCommunityObjectives |> Task.perform identity ) @@ -84,6 +84,17 @@ view loggedIn model = _ -> t "community.not_found" + objectivesContainer children = + div [ class "px-4 pb-4" ] + [ div [ class "container bg-white py-6 sm:py-8 px-3 sm:px-6 rounded-lg mt-4" ] + children + ] + + viewLoading = + objectivesContainer + [ View.Components.loadingLogoAnimated loggedIn.shared.translators "" + ] + content = case loggedIn.selectedCommunity of RemoteData.Loading -> @@ -115,17 +126,27 @@ view loggedIn model = [ if community.hasObjectives then case community.objectives of RemoteData.Success objectives -> - div [ class "px-4 pb-4" ] - [ div [ class "container bg-white py-6 sm:py-8 px-3 sm:px-6 rounded-lg mt-4" ] - (Page.viewTitle (t "community.objectives.title_plural") - :: List.indexedMap (viewObjective loggedIn model community) - objectives - ) + objectivesContainer + (Page.viewTitle (t "community.objectives.title_plural") + :: List.indexedMap (viewObjective loggedIn model community) + objectives + ) + + RemoteData.Loading -> + viewLoading + + RemoteData.NotAsked -> + viewLoading + + RemoteData.Failure err -> + objectivesContainer + [ div [ class "w-full" ] + [ p [ class "text-2xl font-bold text-center" ] [ text (t "community.objectives.error_loading") ] + , p [ class "text-center" ] [ text (Utils.errorToString err) ] + ] + , img [ class "w-1/3 mx-auto", src "/images/error.svg" ] [] ] - _ -> - text "" - else text "" , viewCommunityStats loggedIn.shared.translators community model @@ -332,7 +353,7 @@ type alias UpdateResult = type Msg = NoOp - | RequestedCommunityObjectives + | RequestedReloadCommunityObjectives | CompletedLoadCommunity Community.Model | GotTokenInfo (Result Http.Error Token.Model) -- Objective @@ -347,9 +368,9 @@ update msg model loggedIn = NoOp -> UR.init model - RequestedCommunityObjectives -> + RequestedReloadCommunityObjectives -> UR.init model - |> UR.addExt (LoggedIn.RequestedCommunityField Community.ObjectivesField) + |> UR.addExt (LoggedIn.RequestedReloadCommunityField Community.ObjectivesField) CompletedLoadCommunity community -> UR.init model @@ -402,8 +423,8 @@ msgToString msg = NoOp -> [ "NoOp" ] - RequestedCommunityObjectives -> - [ "RequestedCommunityObjectives" ] + RequestedReloadCommunityObjectives -> + [ "RequestedReloadCommunityObjectives" ] CompletedLoadCommunity _ -> [ "CompletedLoadCommunity" ] From 80b0f1bb9ddebae187721262555bbf27aa82340f Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 15:28:17 -0300 Subject: [PATCH 09/17] Only reload objectives on ActionEditor --- src/elm/Main.elm | 4 +- src/elm/Page/Community/ActionEditor.elm | 61 +++++++++---------------- 2 files changed, 24 insertions(+), 41 deletions(-) diff --git a/src/elm/Main.elm b/src/elm/Main.elm index 96f3288f0..d88337b8b 100755 --- a/src/elm/Main.elm +++ b/src/elm/Main.elm @@ -1274,12 +1274,12 @@ changeRouteTo maybeRoute model = Just (Route.NewAction objectiveId) -> (\l -> ActionEditor.init l objectiveId Nothing) - >> updateStatusWith ActionEditor GotActionEditorMsg model + >> updateLoggedInUResult ActionEditor GotActionEditorMsg model |> withLoggedIn (Route.NewAction objectiveId) Just (Route.EditAction objectiveId actionId) -> (\l -> ActionEditor.init l objectiveId (Just actionId)) - >> updateStatusWith ActionEditor GotActionEditorMsg model + >> updateLoggedInUResult ActionEditor GotActionEditorMsg model |> withLoggedIn (Route.EditAction objectiveId actionId) Just (Route.Claim objectiveId actionId claimId) -> diff --git a/src/elm/Page/Community/ActionEditor.elm b/src/elm/Page/Community/ActionEditor.elm index 35f4ccbd7..051ce784d 100755 --- a/src/elm/Page/Community/ActionEditor.elm +++ b/src/elm/Page/Community/ActionEditor.elm @@ -79,16 +79,16 @@ type alias ActionId = Int -init : LoggedIn.Model -> ObjectiveId -> Maybe ActionId -> ( Model, Cmd Msg ) +init : LoggedIn.Model -> ObjectiveId -> Maybe ActionId -> UpdateResult init loggedIn objectiveId actionId = - ( { status = NotFound - , objectiveId = objectiveId - , actionId = actionId - , form = initForm loggedIn.shared - , multiSelectState = Select.newState "" - } - , LoggedIn.maybeInitWith CompletedLoadCommunity .selectedCommunity loggedIn - ) + { status = Loading + , objectiveId = objectiveId + , actionId = actionId + , form = initForm loggedIn.shared + , multiSelectState = Select.newState "" + } + |> UR.init + |> UR.addExt (LoggedIn.RequestedCommunityField Community.ObjectivesField) @@ -106,6 +106,7 @@ type alias Model = type Status = Authorized + | Loading | NotFound | Unauthorized @@ -473,7 +474,7 @@ type alias UpdateResult = type Msg = NoOp - | CompletedLoadCommunity Community.Model + | CompletedLoadObjectives Community.Model (List Community.Objective) | ClosedAuthModal | OnSelectVerifier (Maybe Profile.Minimal) | OnRemoveVerifier Profile.Minimal @@ -559,38 +560,17 @@ update msg model ({ shared } as loggedIn) = NoOp -> UR.init model - CompletedLoadCommunity community -> + CompletedLoadObjectives community objectives -> if community.creator == loggedIn.accountName then - -- Check the action belongs to the objective let maybeObjective = - -- List.filterMap - -- (\o -> - -- if o.id == model.objectiveId then - -- Just o - -- else - -- Nothing - -- ) - -- community.objectives - -- |> List.head - -- TODO - Nothing + List.find (.id >> (==) model.objectiveId) objectives in case ( maybeObjective, model.actionId ) of ( Just objective, Just actionId ) -> - -- Edit form let maybeAction = - List.filterMap - (\a -> - if a.id == actionId then - Just a - - else - Nothing - ) - objective.actions - |> List.head + List.find (.id >> (==) actionId) objective.actions in case maybeAction of Just action -> @@ -1033,7 +1013,7 @@ update msg model ({ shared } as loggedIn) = |> UR.addCmd (Route.replaceUrl loggedIn.shared.navKey Route.Objectives) |> UR.addExt (ShowFeedback Feedback.Success (t "community.actions.save_success")) -- TODO - This only works sometimes - |> UR.addExt (LoggedIn.ReloadResource LoggedIn.CommunityResource) + |> UR.addExt (LoggedIn.RequestedReloadCommunityField Community.ObjectivesField) |> UR.addBreadcrumb { type_ = Log.DebugBreadcrumb , category = msg @@ -1274,6 +1254,9 @@ view ({ shared } as loggedIn) model = ( RemoteData.NotAsked, _ ) -> Page.fullPageLoading shared + ( _, Loading ) -> + Page.fullPageLoading shared + ( RemoteData.Success community, Authorized ) -> div [ class "bg-white" ] [ Page.viewHeader loggedIn (t "community.actions.title") @@ -1865,8 +1848,8 @@ subscriptions model = receiveBroadcast : LoggedIn.BroadcastMsg -> Maybe Msg receiveBroadcast broadcastMsg = case broadcastMsg of - LoggedIn.CommunityLoaded community -> - Just (CompletedLoadCommunity community) + LoggedIn.CommunityFieldLoaded community (Community.ObjectivesValue objectives) -> + Just (CompletedLoadObjectives community objectives) _ -> Nothing @@ -1897,8 +1880,8 @@ msgToString msg = NoOp -> [ "NoOp" ] - CompletedLoadCommunity _ -> - [ "CompletedLoadCommunity" ] + CompletedLoadObjectives _ _ -> + [ "CompletedLoadObjectives" ] ClosedAuthModal -> [ "ClosedAuthModal" ] From 0340002cac2928038eafd965c26b726ba8c5ea04 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 15:41:04 -0300 Subject: [PATCH 10/17] Requesst objectives field --- src/elm/Page/Community/ObjectiveEditor.elm | 61 ++++++++++++---------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/elm/Page/Community/ObjectiveEditor.elm b/src/elm/Page/Community/ObjectiveEditor.elm index b00b8fa15..dfbdeaa07 100644 --- a/src/elm/Page/Community/ObjectiveEditor.elm +++ b/src/elm/Page/Community/ObjectiveEditor.elm @@ -394,31 +394,10 @@ update msg model loggedIn = if community.creator == loggedIn.accountName then if model.status == Loading then case model.objectiveId of - Just objectiveId -> - case community.objectives of - RemoteData.Success objectives -> - case List.find (\o -> o.id == objectiveId) objectives of - -- TODO - Request reload objectives - Just objective -> - { model - | status = - Editing - |> EditingObjective objective - { description = - MarkdownEditor.init "objective-description" - |> MarkdownEditor.setContents objective.description - , isCompleted = objective.isCompleted - } - |> Authorized - } - |> UR.init - - Nothing -> - { model | status = NotFound } - |> UR.init - - _ -> - model |> UR.init + Just _ -> + model + |> UR.init + |> UR.addExt (LoggedIn.RequestedCommunityField Community.ObjectivesField) Nothing -> { model @@ -437,9 +416,35 @@ update msg model loggedIn = |> UR.init CompletedLoadObjectives objectives -> - -- TODO - model - |> UR.init + case model.objectiveId of + Nothing -> + { model + | status = + Creating + |> CreatingObjective initObjectiveForm + |> Authorized + } + |> UR.init + + Just objectiveId -> + case List.find (.id >> (==) objectiveId) objectives of + Nothing -> + { model | status = NotFound } + |> UR.init + + Just objective -> + { model + | status = + Editing + |> EditingObjective objective + { description = + MarkdownEditor.init "objective-description" + |> MarkdownEditor.setContents objective.description + , isCompleted = objective.isCompleted + } + |> Authorized + } + |> UR.init ClosedAuthModal -> case model.status of From d3e5f5a35d8862627e60d342b952a08b805b7552 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 15:52:47 -0300 Subject: [PATCH 11/17] Fix Join page for logged in users --- src/elm/Page/Join.elm | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/elm/Page/Join.elm b/src/elm/Page/Join.elm index 3d2f45c4b..6b5abbd78 100644 --- a/src/elm/Page/Join.elm +++ b/src/elm/Page/Join.elm @@ -88,7 +88,7 @@ update session msg model = List.map .account community.members |> List.member loggedIn.accountName - redirectToApp = + addAction = if isMember then model.maybeRedirect |> Maybe.withDefault Route.Dashboard @@ -96,10 +96,10 @@ update session msg model = |> UR.addCmd else - identity + UR.addExt (LoggedIn.RequestedCommunityField Community.UploadsField) in UR.init model - |> redirectToApp + |> addAction CompletedSignIn loggedIn (RemoteData.Success (Just { token, user })) -> let @@ -294,18 +294,33 @@ viewAsGuest title guest model = viewAsLoggedIn : String -> LoggedIn.Model -> Model -> Html Msg viewAsLoggedIn title loggedIn model = - case loggedIn.selectedCommunity of - RemoteData.Success community -> - -- div [ class "flex-grow flex" ] - -- [ Community.communityPreviewImage True loggedIn.shared community - -- , view_ False loggedIn.shared community model - -- ] - text "TODO" + case Community.getField loggedIn.selectedCommunity .uploads of + RemoteData.Success ( community, uploads ) -> + let + normalizedCommunity = + { name = community.name + , hasAutoInvite = community.hasAutoInvite + , description = community.description + , uploads = uploads + , memberCount = community.memberCount + , website = community.website + } + in + div [ class "flex-grow flex" ] + [ Community.communityPreviewImage True loggedIn.shared normalizedCommunity + , view_ False loggedIn.shared normalizedCommunity model + ] - RemoteData.Failure err -> + RemoteData.Failure (Community.CommunityError err) -> Page.fullPageGraphQLError title err - _ -> + RemoteData.Failure (Community.FieldError err) -> + Page.fullPageGraphQLError title err + + RemoteData.Loading -> + viewLoading loggedIn.shared + + RemoteData.NotAsked -> viewLoading loggedIn.shared From 20478c14d2a50ae45d7ee116ee105e8d7156a344 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 16:06:31 -0300 Subject: [PATCH 12/17] Set fields as loading while fetching them --- src/elm/Community.elm | 11 +++++++++++ src/elm/Session/LoggedIn.elm | 18 ++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/elm/Community.elm b/src/elm/Community.elm index fc0abb855..36d3b9995 100755 --- a/src/elm/Community.elm +++ b/src/elm/Community.elm @@ -32,6 +32,7 @@ module Community exposing , newCommunitySubscription , queryForField , queryForFields + , setFieldAsLoading , setFieldValue , subdomainQuery , symbolQuery @@ -159,6 +160,16 @@ setFieldValue fieldValue model = { model | uploads = RemoteData.Success uploads } +setFieldAsLoading : Field -> Model -> Model +setFieldAsLoading field model = + case field of + ObjectivesField -> + { model | objectives = RemoteData.Loading } + + UploadsField -> + { model | uploads = RemoteData.Loading } + + isFieldLoading : Field -> Model -> Bool isFieldLoading field model = case field of diff --git a/src/elm/Session/LoggedIn.elm b/src/elm/Session/LoggedIn.elm index 20917d792..ec3aaeba2 100755 --- a/src/elm/Session/LoggedIn.elm +++ b/src/elm/Session/LoggedIn.elm @@ -901,7 +901,6 @@ updateExternal externalMsg ({ shared } as model) = else case Community.maybeFieldValue field community of Nothing -> - -- TODO - Set field as loading { defaultResult | cmd = Community.queryForField community.symbol @@ -909,6 +908,12 @@ updateExternal externalMsg ({ shared } as model) = model.authToken field (CompletedLoadCommunityField community) + , model = + { model + | selectedCommunity = + Community.setFieldAsLoading field community + |> RemoteData.Success + } } Just fieldValue -> @@ -1146,12 +1151,17 @@ update msg model = newCommunity = Community.mergeFields newModel.selectedCommunity community + |> (\comm -> + List.foldl Community.setFieldAsLoading + comm + newModel.queuedCommunityFields + ) in - UR.init newModel + { newModel | selectedCommunity = RemoteData.Success newCommunity } + |> UR.init |> UR.addCmd cmd |> UR.addCmd (Ports.getRecentSearches ()) - |> UR.addExt (CommunityLoaded community |> Broadcast) - -- TODO - Set fields as loading + |> UR.addExt (CommunityLoaded newCommunity |> Broadcast) |> UR.addCmd (Community.queryForFields community.symbol newModel.shared From d29a25f2262a944a98140d17e6f418e421111a28 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 16:07:19 -0300 Subject: [PATCH 13/17] Only reload objectives on ObjectiveEditor --- src/elm/Page/Community/ObjectiveEditor.elm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elm/Page/Community/ObjectiveEditor.elm b/src/elm/Page/Community/ObjectiveEditor.elm index dfbdeaa07..595aab470 100644 --- a/src/elm/Page/Community/ObjectiveEditor.elm +++ b/src/elm/Page/Community/ObjectiveEditor.elm @@ -801,7 +801,7 @@ update msg model loggedIn = UR.init model |> UR.addExt (ShowFeedback Feedback.Success (t "community.objectives.create_success")) -- TODO - This only works sometimes - |> UR.addExt (LoggedIn.ReloadResource LoggedIn.CommunityResource) + |> UR.addExt (LoggedIn.RequestedReloadCommunityField Community.ObjectivesField) |> UR.addCmd (Route.replaceUrl loggedIn.shared.navKey Route.Community) GotSaveObjectiveResponse (Err v) -> From 25fe5d0e4cdbb24d8720551a955be9acd56accaf Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 16:07:28 -0300 Subject: [PATCH 14/17] Remove unnecessary comment --- src/elm/Page/Community/Settings/Info.elm | 1 - 1 file changed, 1 deletion(-) diff --git a/src/elm/Page/Community/Settings/Info.elm b/src/elm/Page/Community/Settings/Info.elm index 44d30be4c..af33204f7 100644 --- a/src/elm/Page/Community/Settings/Info.elm +++ b/src/elm/Page/Community/Settings/Info.elm @@ -565,7 +565,6 @@ update msg model ({ shared } as loggedIn) = newUploads = case ( community.uploads, model.coverPhoto ) of - -- TODO - Check this ( RemoteData.Success uploads, RemoteData.Success coverPhoto ) -> RemoteData.Success (coverPhoto :: uploads) From 49dec24152fbbdb0d7ae6b3ba735e5f44f3e2ad1 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 16:19:51 -0300 Subject: [PATCH 15/17] Remove unnecessary comment --- src/elm/Community.elm | 1 - 1 file changed, 1 deletion(-) diff --git a/src/elm/Community.elm b/src/elm/Community.elm index 36d3b9995..606aeb9b3 100755 --- a/src/elm/Community.elm +++ b/src/elm/Community.elm @@ -248,7 +248,6 @@ communitySelectionSet = |> with Community.hasKyc |> with Community.autoInvite |> with (Community.validators (Eos.nameSelectionSet Profile.account)) - -- |> with (Community.uploads Upload.url) |> SelectionSet.hardcoded RemoteData.NotAsked |> with Community.website From 185051cac92dc356db8ffd32d3d49a99dfa40f41 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Tue, 28 Sep 2021 16:21:33 -0300 Subject: [PATCH 16/17] Use UpdateResult in CommunityPage.init --- src/elm/Main.elm | 2 +- src/elm/Page/Community.elm | 17 ++++------------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/elm/Main.elm b/src/elm/Main.elm index d88337b8b..0bebb2539 100755 --- a/src/elm/Main.elm +++ b/src/elm/Main.elm @@ -1224,7 +1224,7 @@ changeRouteTo maybeRoute model = Just Route.Community -> (\l -> CommunityPage.init l) - >> updateStatusWith Community GotCommunityMsg model + >> updateLoggedInUResult Community GotCommunityMsg model |> withLoggedIn Route.Community Just Route.CommunitySettings -> diff --git a/src/elm/Page/Community.elm b/src/elm/Page/Community.elm index 2b8a1c1fa..61deb0e73 100755 --- a/src/elm/Page/Community.elm +++ b/src/elm/Page/Community.elm @@ -23,7 +23,6 @@ import Page import RemoteData exposing (RemoteData) import Session.LoggedIn as LoggedIn exposing (External(..)) import Session.Shared exposing (Shared, Translators) -import Task import Time exposing (Posix, posixToMillis) import Token import UpdateResult as UR @@ -36,11 +35,11 @@ import View.MarkdownEditor -- INIT -init : LoggedIn.Model -> ( Model, Cmd Msg ) +init : LoggedIn.Model -> UpdateResult init loggedIn = - ( initModel loggedIn - , Task.succeed RequestedReloadCommunityObjectives |> Task.perform identity - ) + initModel loggedIn + |> UR.init + |> UR.addExt (LoggedIn.RequestedReloadCommunityField Community.ObjectivesField) initModel : LoggedIn.Model -> Model @@ -353,7 +352,6 @@ type alias UpdateResult = type Msg = NoOp - | RequestedReloadCommunityObjectives | CompletedLoadCommunity Community.Model | GotTokenInfo (Result Http.Error Token.Model) -- Objective @@ -368,10 +366,6 @@ update msg model loggedIn = NoOp -> UR.init model - RequestedReloadCommunityObjectives -> - UR.init model - |> UR.addExt (LoggedIn.RequestedReloadCommunityField Community.ObjectivesField) - CompletedLoadCommunity community -> UR.init model |> UR.addCmd (Token.getToken loggedIn.shared community.symbol GotTokenInfo) @@ -423,9 +417,6 @@ msgToString msg = NoOp -> [ "NoOp" ] - RequestedReloadCommunityObjectives -> - [ "RequestedReloadCommunityObjectives" ] - CompletedLoadCommunity _ -> [ "CompletedLoadCommunity" ] From d4388ce1a554af1668fdf178547db94814d24366 Mon Sep 17 00:00:00 2001 From: Henrique Buss Date: Wed, 29 Sep 2021 15:23:06 -0300 Subject: [PATCH 17/17] Add docs to Field, FieldValue and FieldError --- src/elm/Community.elm | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/elm/Community.elm b/src/elm/Community.elm index 606aeb9b3..4a9e8ef07 100755 --- a/src/elm/Community.elm +++ b/src/elm/Community.elm @@ -120,16 +120,55 @@ type alias Model = } +{-| In order to be able to query for fields separately from the community (such +as objectives and uploads), we need to add a `Field` constructor to represent +that field. The constructor's name should be the name of the field followed by +`Field` (e.g. `ObjectivesField`). + +In order to have a nice API, we also need types to wrap the success and error +cases. That's why we have `FieldValue` and `FieldError`. + +If you want to add a new field that isn't loaded by default (usually Lists are +good candidates): + +1. Add the field to the `Model`. It's type should be in the format + `RemoteData (Graphql.Http.Error field) field` +2. Add a new constructor to this `Field` type following the practices described above +3. Add a new constructor to `FieldValue` (see `FieldValue`'s documentation for + more info) +4. Fill in the functions that use `Field` and `FieldValue` (the compiler will + let you know which ones) + +Pages can use this type to request separate fields from `LoggedIn`, using +`LoggedIn.External` messages, specifying which field they want. There are two +variants they can use to do so: + +1. `RequestedCommunityField`: Checks if the field is loaded. If so, send a + `BroadcastMsg` with the field. If not, queries the backend for that field, + and once the result comes in, sends a `BroadcastMsg` +2. `RequestedReloadCommunityField`: Always queries for the field, and sends the + result as a `BroadcastMsg` + +-} type Field = ObjectivesField | UploadsField +{-| `FieldValue` is useful to wrap results of queries for fields that aren't +loaded in by default with the community (such as objectives and uploads). The +constructor's name should be the name of the field followed by `Value`, and +should hold the actual value of that field (e.g. `ObjectivesValue (List Objetive)`). +-} type FieldValue = ObjectivesValue (List Objective) | UploadsValue (List String) +{-| When we want to extract a field that is not loaded by default with the +community, and there is an error, we need to know if it was an error when +fetching the community or when fetching the actual field. +-} type FieldError a = CommunityError (Graphql.Http.Error (Maybe Model)) | FieldError a