diff --git a/src/schema/schema.graphql b/src/schema/schema.graphql index adeaa0cf..5fccb111 100644 --- a/src/schema/schema.graphql +++ b/src/schema/schema.graphql @@ -1,3 +1,20 @@ +type Query { + """Fetches an object given its ID""" + node( + """The ID of an object""" + id: ID! + ): Node + app: App + user(userId: String!): User + userImpact(userId: String!, charityId: String!): UserImpact +} + +"""An object with an ID""" +interface Node { + """The id of the object.""" + id: ID! +} + """Global app fields""" type App implements Node { """The ID of an object""" @@ -7,272 +24,250 @@ type App implements Node { referralVcReward: Int """All the widgets""" - widgets(after: String, first: Int, before: String, last: Int): WidgetConnection + widgets( + """Returns the items in the list that come after the specified cursor.""" + after: String + + """Returns the first n items from the list.""" + first: Int + + """Returns the items in the list that come before the specified cursor.""" + before: String + + """Returns the last n items from the list.""" + last: Int + ): WidgetConnection """One of the charities""" charity(charityId: String!): Charity """All the charities""" - charities(after: String, first: Int, before: String, last: Int, filters: CharitiesFilters): CharityConnection + charities( + """Returns the items in the list that come after the specified cursor.""" + after: String - """All the causes""" - causes(after: String, first: Int, before: String, last: Int, filters: CausesFilters): CauseConnection + """Returns the first n items from the list.""" + first: Int - """Get all the "legacy" (uncategorized) background Images""" - backgroundImages(after: String, first: Int, before: String, last: Int): BackgroundImageConnection + """Returns the items in the list that come before the specified cursor.""" + before: String - """Campaigns (or "charity spotlights") shown to users.""" - campaign: Campaign + """Returns the last n items from the list.""" + last: Int + filters: CharitiesFilters + ): CharityConnection - """All the search engines""" - searchEngines: SearchEngineConnection -} + """All the causes""" + causes( + """Returns the items in the list that come after the specified cursor.""" + after: String -"""A background image""" -type BackgroundImage implements Node { - """The ID of an object""" - id: ID! + """Returns the first n items from the list.""" + first: Int - """the background image name""" - name: String + """Returns the items in the list that come before the specified cursor.""" + before: String - """The image filename""" - image: String + """Returns the last n items from the list.""" + last: Int + filters: CausesFilters + ): CauseConnection - """The image file URL""" - imageURL: String + """Get all the "legacy" (uncategorized) background Images""" + backgroundImages( + """Returns the items in the list that come after the specified cursor.""" + after: String - """the category that the image falls into""" - category: String! + """Returns the first n items from the list.""" + first: Int - """The image thumbnail filename""" - thumbnail: String + """Returns the items in the list that come before the specified cursor.""" + before: String - """The image thumbnail URL""" - thumbnailURL: String + """Returns the last n items from the list.""" + last: Int + ): BackgroundImageConnection - """ISO datetime string of when the background image was last set""" - timestamp: String + """Campaigns (or "charity spotlights") shown to users.""" + campaign: Campaign + + """All the search engines""" + searchEngines: SearchEngineConnection } """A connection to a list of items.""" -type BackgroundImageConnection { +type WidgetConnection { """Information to aid in pagination.""" pageInfo: PageInfo! """A list of edges.""" - edges: [BackgroundImageEdge] + edges: [WidgetEdge] +} + +"""Information about pagination in a connection.""" +type PageInfo { + """When paginating forwards, are there more items?""" + hasNextPage: Boolean! + + """When paginating backwards, are there more items?""" + hasPreviousPage: Boolean! + + """When paginating backwards, the cursor to continue.""" + startCursor: String + + """When paginating forwards, the cursor to continue.""" + endCursor: String } """An edge in a connection.""" -type BackgroundImageEdge { +type WidgetEdge { """The item at the end of the edge""" - node: BackgroundImage + node: Widget """A cursor for use in pagination""" cursor: String! } -"""Campaigns (or "charity spotlights") shown to users.""" -type Campaign { - """The ID of the campaign""" - campaignId: String +"""App widget""" +type Widget implements Node { + """The ID of an object""" + id: ID! - """The charity that this campaign features""" - charity: Charity + """Widget display name""" + name: String - """The text content for the campaign""" - content: CampaignContent! + """Widget type""" + type: String - """ - The text content for the campaign when it has finished (past the end time) - """ - endContent: CampaignContent @deprecated(reason: "The content returned by the server will automatically change when the campaign ends.") + """Widget icon""" + icon: String - """Whether or not the campaign should currently show to users""" - isLive: Boolean! + """The Widget enabled state""" + enabled: Boolean - """Information on progress toward a target impact goal for the campaign""" - goal: CampaignGoal + """The Widget visible state""" + visible: Boolean - """The number of new users who joined during this campaign.""" - numNewUsers: Int @deprecated(reason: "Replaced by the generalized\"goal\" data.") + """Widget data.""" + data: String - """Whether to show a countdown timer for when the campaign will end""" - showCountdownTimer: Boolean! + """Widget user specific configuration.""" + config: String - """ - Whether to show a button to donate hearts to the charity featured in the - campaign -- which requires the "charity " field to be defined - """ - showHeartsDonationButton: Boolean! + """Widget general configuration.""" + settings: String +} - """ - Whether to show a progress bar -- which requires the "goal" field to be defined - """ - showProgressBar: Boolean! +"""A charitable charity""" +type Charity implements Node { + """The ID of an object""" + id: ID! - """Whether to show social sharing buttons""" - showSocialSharing: Boolean! + """the charity name""" + name: String - """Social sharing buttons""" - socialSharing: CampaignSocialSharing + """the charity category""" + category: String - """Theming/style for the campaign""" - theme: CampaignTheme + """the charity website""" + website: String - """The start and end times (in ISO timestamps) for the campaign""" - time: CampaignTime! -} + """the charity description""" + description: String -"""Text content for campaigns""" -type CampaignContent { - """The campaign title, using markdown""" - titleMarkdown: String! + """the charity impact message""" + impact: String - """ - The primary campaign text content (paragraphs, links, etc.), using markdown - """ - descriptionMarkdown: String! + """the charity logo image URI""" + logo: String - """ - Additional campaign text content (paragraphs, links, etc.), using markdown - """ - descriptionMarkdownTwo: String -} + """the charity post-donation image URI""" + image: String -"""Information on progress toward a target impact goal for the campaign""" -type CampaignGoal { - """ - The goal number of whatever impact units the campaign is hoping to achieve - """ - targetNumber: Float! + """An optional caption for the post-donation image""" + imageCaption: String - """ - The current number of whatever impact units the campaign is hoping to achieve - """ - currentNumber: Float! + """The number of VC the charity has received in a given time period.""" + vcReceived(startTime: String, endTime: String): Int - """ - The English word for the impact unit, singular (e.g. Heart, dollar, puppy) - """ - impactUnitSingular: String! + """Impact Metrics that belong to this Charity""" + impactMetrics: [ImpactMetric] +} - """ - The English word for the impact unit, plural (e.g. Hearts, dollars, puppies) - """ - impactUnitPlural: String! +"""An instance of ImpactMetric""" +type ImpactMetric implements Node { + """The ID of an object""" + id: ID! - """ - The past-tense participle English verb that describes achieving the impact unit (e.g. given, raised, adopted) - """ - impactVerbPastParticiple: String! + """Charity ID that this impact metric belongs to""" + charity: Charity """ - The simple past-tense English verb that describes achieving the impact unit (e.g. gave, raised, adopted) + Dollar amount (in micro USDs) required to achieve an instance of this ImpactMetric """ - impactVerbPastTense: String! + dollarAmount: Int! + + """Markdown description of this ImpactMetric""" + description: String! """ - If true, do not display a currentNumber greater than the targetNumber. Instead, limit goal progress to 100% of the target. + Markdown. A shorter version of the description that answers "why this impact matters". """ - limitProgressToTargetMax: Boolean! + whyValuableDescription: String! """ - Whether the progress bar should have labels of the current number and goal number + Metric title. Should be placeable in a sentence. Example: "1 home visit" """ - showProgressBarLabel: Boolean! + metricTitle: String! """ - Whether the progress bar should have an end-of-campaign summary text of the progress + Impact action title. Should be a longer title with a verb as well as a noun. Example: "Provide 1 visit from a community health worker" """ - showProgressBarEndText: Boolean! -} - -"""Information on progress toward a target impact goal for the campaign""" -type CampaignSocialSharing { - """The URL to share""" - url: String! - - """Props for the email social sharing button""" - EmailShareButtonProps: CampaignSocialSharingEmailProps - - """Props for the Facebook social sharing button""" - FacebookShareButtonProps: CampaignSocialSharingFacebookProps + impactTitle: String! - """Props for the Reddit social sharing button""" - RedditShareButtonProps: CampaignSocialSharingRedditProps + """Whether or not this GroupImpactMetric is still active""" + active: Boolean! +} - """Props for the Tumblr social sharing button""" - TumblrShareButtonProps: CampaignSocialSharingTumblrProps +"""A connection to a list of items.""" +type CharityConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! - """Props for the Twitter social sharing button""" - TwitterShareButtonProps: CampaignSocialSharingTwitterProps + """A list of edges.""" + edges: [CharityEdge] } -"""Props for the email social sharing button""" -type CampaignSocialSharingEmailProps { - """The email subject""" - subject: String! +"""An edge in a connection.""" +type CharityEdge { + """The item at the end of the edge""" + node: Charity - """The email body""" - body: String! + """A cursor for use in pagination""" + cursor: String! } -"""Props for the Facebook social sharing button""" -type CampaignSocialSharingFacebookProps { - """The text to share to Facebook""" - quote: String! -} - -"""Props for the Reddit social sharing button""" -type CampaignSocialSharingRedditProps { - """The text to share to Reddit""" - title: String! -} - -"""Props for the Tumblr social sharing button""" -type CampaignSocialSharingTumblrProps { - """The Tumblr title""" - title: String! - - """The Tumblr caption""" - caption: String! -} - -"""Props for the Twitter social sharing button""" -type CampaignSocialSharingTwitterProps { - """The text to share to Twitter""" - title: String! - - """A list of Twitter handles that relate to the post""" - related: [String]! -} - -"""Theming/styling for the campaign""" -type CampaignTheme { - """ - The goal number of whatever impact units the campaign is hoping to achieve - """ - color: CampaignThemeColor +"""Fields on which to filter the list of charities.""" +input CharitiesFilters { + isPermanentPartner: Boolean } -"""Color theming for the campaign""" -type CampaignThemeColor { - """The primary color for the theme""" - main: String! +"""A connection to a list of items.""" +type CauseConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! - """The lighter color for the theme""" - light: String! + """A list of edges.""" + edges: [CauseEdge] } -"""The start and end times (in ISO timestamps) for the campaign""" -type CampaignTime { - """The start time of the campaign as an ISO timestamp""" - start: String! +"""An edge in a connection.""" +type CauseEdge { + """The item at the end of the edge""" + node: Cause - """The end time of the campaign as an ISO timestamp""" - end: String! + """A cursor for use in pagination""" + cursor: String! } """all cause specific data and ui content""" @@ -325,24 +320,6 @@ type Cause implements Node { groupImpactMetric: GroupImpactMetric } -"""A connection to a list of items.""" -type CauseConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [CauseEdge] -} - -"""An edge in a connection.""" -type CauseEdge { - """The item at the end of the edge""" - node: Cause - - """A cursor for use in pagination""" - cursor: String! -} - """The type of charitable impact that's enabled for this cause""" enum causeImpactType { none @@ -350,11 +327,6 @@ enum causeImpactType { group } -"""Fields on which to filter the list of causes.""" -input CausesFilters { - isAvailableToSelect: Boolean -} - """cause specific UI content around impact""" type CauseSpecificImpactUI { """markdown string: copy for ImpactCounter for normal case""" @@ -404,536 +376,593 @@ type CauseTheming { secondaryColor: String! } -"""Fields on which to filter the list of charities.""" -input CharitiesFilters { - isPermanentPartner: Boolean +"""cause specific UI content around sharing""" +type SharingUICopy { + """markdown for modal title""" + title: String! + + """markdown for modal subtitle""" + subtitle: String! + + """ + value to use for img switch statement on frontend, probably ‘cats’ or ‘seas’ + """ + imgCategory: String! + + """Image to use in email invite dialog""" + shareImage: String! + + """Image shown after email invite sent""" + sentImage: String! + + """copy for reddit button""" + redditButtonTitle: String! + + """copy for facebook button""" + facebookButtonTitle: String! + + """copy for twitter button""" + twitterButtonTitle: String! + + """copy for tumblr button""" + tumblrTitle: String! + + """copy for tumblr caption""" + tumblrCaption: String! } -"""A charitable charity""" -type Charity implements Node { - """The ID of an object""" - id: ID! +"""cause specific UI content around onboarding""" +type OnboardingUICopy { + """the steps array in onboarding""" + steps: [onboardingUIStep]! - """the charity name""" - name: String + """ + markdown string shown when prompting the user to open their first tab, currently info about cat treats + """ + firstTabIntroDescription: String! +} - """the charity category""" - category: String +"""ui content for each onboarding step""" +type onboardingUIStep { + """markdown title for onboarding step""" + title: String! - """the charity website""" - website: String + """markdown subtitle for onboarding step""" + subtitle: String! - """the charity description""" - description: String + """name of image to show""" + imgName: String! +} - """the charity impact message""" - impact: String +"""A specific instance of GroupImpactMetric""" +type GroupImpactMetric implements Node { + """The ID of an object""" + id: ID! - """the charity logo image URI""" - logo: String + """The cause ID this GroupImpactMetric belongs to""" + cause: Cause - """the charity post-donation image URI""" - image: String + """Information about the ImpactMetric""" + impactMetric: ImpactMetric - """An optional caption for the post-donation image""" - imageCaption: String + """ + The micro USD amount raised for this instance of GroupImpactMetric so far + """ + dollarProgress: Int! - """The number of VC the charity has received in a given time period.""" - vcReceived(startTime: String, endTime: String): Int + """ + The micro USD amount raised for this instance of GroupImpactMetric so far + """ + dollarGoal: Int! - """Impact Metrics that belong to this Charity""" - impactMetrics: [ImpactMetric] + """ISO datetime string of when this GroupImpactMetric was started""" + dateStarted: String + + """ISO datetime string of when this GroupImpactMetric was ended""" + dateCompleted: String +} + +"""Fields on which to filter the list of causes.""" +input CausesFilters { + isAvailableToSelect: Boolean } """A connection to a list of items.""" -type CharityConnection { +type BackgroundImageConnection { """Information to aid in pagination.""" pageInfo: PageInfo! """A list of edges.""" - edges: [CharityEdge] + edges: [BackgroundImageEdge] } """An edge in a connection.""" -type CharityEdge { +type BackgroundImageEdge { """The item at the end of the edge""" - node: Charity + node: BackgroundImage """A cursor for use in pagination""" cursor: String! } -input CreateInvitedUsersInput { - inviterId: String! - invitedEmails: [String]! - inviterName: String - inviterMessage: String - clientMutationId: String -} +"""A background image""" +type BackgroundImage implements Node { + """The ID of an object""" + id: ID! -type CreateInvitedUsersPayload { - successfulEmailAddresses: [successfulEmailAddresses] - failedEmailAddresses: [failedEmailAddresses] - clientMutationId: String -} + """the background image name""" + name: String -input CreateNewMissionInput { - userId: String! - squadName: String! - clientMutationId: String -} + """The image filename""" + image: String -type CreateNewMissionPayload { - """the current active mission for a user""" - currentMission: Mission - clientMutationId: String -} + """The image file URL""" + imageURL: String -input CreateNewUserInput { - userId: String! - email: String - referralData: ReferralData - experimentGroups: ExperimentGroups - extensionInstallId: String - extensionInstallTimeApprox: String - v4BetaEnabled: Boolean - missionId: String - causeId: String - clientMutationId: String -} + """the category that the image falls into""" + category: String! -type CreateNewUserPayload { - user: User - clientMutationId: String -} + """The image thumbnail filename""" + thumbnail: String -input CreateSearchEnginePromptLogInput { - userId: String! - searchEnginePrompted: String! - switched: Boolean! - clientMutationId: String -} + """The image thumbnail URL""" + thumbnailURL: String -type CreateSearchEnginePromptLogPayload { - success: Boolean! - user: User - clientMutationId: String + """ISO datetime string of when the background image was last set""" + timestamp: String } -input CreateSfacExtensionPromptResponseInput { - userId: String! - browser: String! - accepted: Boolean! - clientMutationId: String -} +"""Campaigns (or "charity spotlights") shown to users.""" +type Campaign { + """The ID of the campaign""" + campaignId: String -type CreateSfacExtensionPromptResponsePayload { - user: User - clientMutationId: String -} + """The charity that this campaign features""" + charity: Charity -input CreateSquadInvitesInput { - inviterId: String! - invitedEmails: [String]! - inviterName: String! - inviterMessage: String - clientMutationId: String -} + """The text content for the campaign""" + content: CampaignContent! -type CreateSquadInvitesPayload { - """the current active mission for a user""" - currentMission: Mission - clientMutationId: String -} + """ + The text content for the campaign when it has finished (past the end time) + """ + endContent: CampaignContent @deprecated(reason: "The content returned by the server will automatically change when the campaign ends.") -input CreateUserExperimentInput { - userId: String! - experimentId: String! - variationId: Int! - variationValueStr: String - clientMutationId: String -} + """Whether or not the campaign should currently show to users""" + isLive: Boolean! -type CreateUserExperimentPayload { - success: Boolean! - clientMutationId: String -} + """Information on progress toward a target impact goal for the campaign""" + goal: CampaignGoal -input CreateVideoAdLogInput { - userId: String! - clientMutationId: String -} + """The number of new users who joined during this campaign.""" + numNewUsers: Int @deprecated(reason: "Replaced by the generalized \"goal\" data.") -type CreateVideoAdLogPayload { - VideoAdLog: VideoAdLog - clientMutationId: String -} + """Whether to show a countdown timer for when the campaign will end""" + showCountdownTimer: Boolean! -"""For expected errors, such as during form validation""" -type CustomError { - """The error code""" - code: String + """ + Whether to show a button to donate hearts to the charity featured in the campaign -- which requires the "charity " field to be defined + """ + showHeartsDonationButton: Boolean! - """The error message""" - message: String -} + """ + Whether to show a progress bar -- which requires the "goal" field to be defined + """ + showProgressBar: Boolean! -input DeleteUserInput { - userId: String! - clientMutationId: String -} + """Whether to show social sharing buttons""" + showSocialSharing: Boolean! -type DeleteUserPayload { - success: Boolean! - clientMutationId: String -} + """Social sharing buttons""" + socialSharing: CampaignSocialSharing -input DonateVcInput { - userId: String! - charityId: String! - vc: Int! - clientMutationId: String -} + """Theming/style for the campaign""" + theme: CampaignTheme -type DonateVcPayload { - user: User - errors: [CustomError] - clientMutationId: String + """The start and end times (in ISO timestamps) for the campaign""" + time: CampaignTime! } -"""An object representing a single revenue value""" -input EncodedRevenueValue { - encodingType: EncodedRevenueValueTypeEnum! +"""Text content for campaigns""" +type CampaignContent { + """The campaign title, using markdown""" + titleMarkdown: String! """ - A string that we can decode to a revenue value (float) using the "encodingType" method + The primary campaign text content (paragraphs, links, etc.), using markdown """ - encodedValue: String! - adSize: String -} + descriptionMarkdown: String! -""" -The type of transformation we should use to resolve the object into a revenue value -""" -enum EncodedRevenueValueTypeEnum { - AMAZON_CPM + """ + Additional campaign text content (paragraphs, links, etc.), using markdown + """ + descriptionMarkdownTwo: String } -"""persistant awards calculated at end of mission""" -type EndOfMissionAward { - """users ID""" - user: String! +"""Information on progress toward a target impact goal for the campaign""" +type CampaignGoal { + """ + The goal number of whatever impact units the campaign is hoping to achieve + """ + targetNumber: Float! - """the string name of the particular award""" - awardType: String! + """ + The current number of whatever impact units the campaign is hoping to achieve + """ + currentNumber: Float! - """the numerical stat for the award, such as number of tabs""" - unit: Int! -} + """ + The English word for the impact unit, singular (e.g. Heart, dollar, puppy) + """ + impactUnitSingular: String! -"""Action taken in response to the "referral notification" experiment.""" -enum ExperimentActionReferralNotification { - NONE - DISMISS - CLICK -} + """ + The English word for the impact unit, plural (e.g. Hearts, dollars, puppies) + """ + impactUnitPlural: String! -"""The actions a user may take in an experiment""" -input ExperimentActions { - searchIntro: ExperimentActionSearchIntro - referralNotification: ExperimentActionReferralNotification -} + """ + The past-tense participle English verb that describes achieving the impact unit (e.g. given, raised, adopted) + """ + impactVerbPastParticiple: String! -"""Action taken in response to the "search intro" experiment.""" -enum ExperimentActionSearchIntro { - NONE - DISMISS - CLICK + """ + The simple past-tense English verb that describes achieving the impact unit (e.g. gave, raised, adopted) + """ + impactVerbPastTense: String! + + """ + If true, do not display a currentNumber greater than the targetNumber. Instead, limit goal progress to 100% of the target. + """ + limitProgressToTargetMax: Boolean! + + """ + Whether the progress bar should have labels of the current number and goal number + """ + showProgressBarLabel: Boolean! + + """ + Whether the progress bar should have an end-of-campaign summary text of the progress + """ + showProgressBarEndText: Boolean! } -"""The actions a user has taken in an experiment""" -type ExperimentActionsOutput { - searchIntro: ExperimentActionSearchIntro - referralNotification: ExperimentActionReferralNotification +"""Information on progress toward a target impact goal for the campaign""" +type CampaignSocialSharing { + """The URL to share""" + url: String! + + """Props for the email social sharing button""" + EmailShareButtonProps: CampaignSocialSharingEmailProps + + """Props for the Facebook social sharing button""" + FacebookShareButtonProps: CampaignSocialSharingFacebookProps + + """Props for the Reddit social sharing button""" + RedditShareButtonProps: CampaignSocialSharingRedditProps + + """Props for the Tumblr social sharing button""" + TumblrShareButtonProps: CampaignSocialSharingTumblrProps + + """Props for the Twitter social sharing button""" + TwitterShareButtonProps: CampaignSocialSharingTwitterProps } -"""The test of showing an explanation of why there are ads""" -enum ExperimentGroupAdExplanation { - NONE - DEFAULT - SHOW_EXPLANATION +"""Props for the email social sharing button""" +type CampaignSocialSharingEmailProps { + """The email subject""" + subject: String! + + """The email body""" + body: String! } -"""The test of allowing anonymous user authentication""" -enum ExperimentGroupAnonSignIn { - NONE - AUTHED_USER_ONLY - ANONYMOUS_ALLOWED +"""Props for the Facebook social sharing button""" +type CampaignSocialSharingFacebookProps { + """The text to share to Facebook""" + quote: String! } -"""The test of showing only one ad to new users""" -enum ExperimentGroupOneAdForNewUsers { - NONE - DEFAULT - ONE_AD_AT_FIRST +"""Props for the Reddit social sharing button""" +type CampaignSocialSharingRedditProps { + """The text to share to Reddit""" + title: String! } -"""The test of showing a notification to ask users to recruit friends""" -enum ExperimentGroupReferralNotification { - NONE - NO_NOTIFICATION - COPY_A - COPY_B - COPY_C - COPY_D - COPY_E +"""Props for the Tumblr social sharing button""" +type CampaignSocialSharingTumblrProps { + """The Tumblr title""" + title: String! + + """The Tumblr caption""" + caption: String! } -"""The experimental groups to which the user is assigned""" -input ExperimentGroups { - anonSignIn: ExperimentGroupAnonSignIn - variousAdSizes: ExperimentGroupVariousAdSizes - thirdAd: ExperimentGroupThirdAd - oneAdForNewUsers: ExperimentGroupOneAdForNewUsers - adExplanation: ExperimentGroupAdExplanation - searchIntro: ExperimentGroupSearchIntro - referralNotification: ExperimentGroupReferralNotification +"""Props for the Twitter social sharing button""" +type CampaignSocialSharingTwitterProps { + """The text to share to Twitter""" + title: String! + + """A list of Twitter handles that relate to the post""" + related: [String]! } -"""The test of showing an introduction message to Search for a Cause""" -enum ExperimentGroupSearchIntro { - NONE - NO_INTRO - INTRO_A - INTRO_HOMEPAGE +"""Theming/styling for the campaign""" +type CampaignTheme { + """ + The goal number of whatever impact units the campaign is hoping to achieve + """ + color: CampaignThemeColor } -"""The test of enabling a third ad""" -enum ExperimentGroupThirdAd { - NONE - TWO_ADS - THREE_ADS +"""Color theming for the campaign""" +type CampaignThemeColor { + """The primary color for the theme""" + main: String! + + """The lighter color for the theme""" + light: String! } -"""The test of enabling many different ad sizes""" -enum ExperimentGroupVariousAdSizes { - NONE - STANDARD - VARIOUS +"""The start and end times (in ISO timestamps) for the campaign""" +type CampaignTime { + """The start time of the campaign as an ISO timestamp""" + start: String! + + """The end time of the campaign as an ISO timestamp""" + end: String! } -type failedEmailAddresses { - email: String - error: String +"""A connection to a list of items.""" +type SearchEngineConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [SearchEngineEdge] } -"""Feature name and variation value pair applicable to a user.""" -type Feature { - """Name of the Feature""" - featureName: String! +"""An edge in a connection.""" +type SearchEngineEdge { + """The item at the end of the edge""" + node: SearchEngine - """the value of the variation for this specific user""" - variation: String! + """A cursor for use in pagination""" + cursor: String! } -"""A specific instance of GroupImpactMetric""" -type GroupImpactMetric implements Node { - """The ID of an object""" - id: ID! +"""all important data for a search engine.""" +type SearchEngine implements Node { + """Engine's id""" + engineId: String! - """The cause ID this GroupImpactMetric belongs to""" - cause: Cause + """Name of the Search Engine""" + name: String! - """Information about the ImpactMetric""" - impactMetric: ImpactMetric + """what order to display the search engine in a list""" + rank: Int! - """ - The micro USD amount raised for this instance of GroupImpactMetric so far - """ - dollarProgress: Int! + """Whether or not the user can earn extra impact with this Search Engine""" + isCharitable: Boolean! - """ - The micro USD amount raised for this instance of GroupImpactMetric so far - """ - dollarGoal: Int! + """Display string to display in the search bar""" + inputPrompt: String! - """ISO datetime string of when this GroupImpactMetric was started""" - dateStarted: String + """The ID of an object""" + id: ID! - """ISO datetime string of when this GroupImpactMetric was ended""" - dateCompleted: String + """ + A search destination URL, with a {searchTerms} placeholder for the client to replace. Use `user.searchEngine` if the user is authenticated. + """ + searchUrl: String! } -"""An instance of ImpactMetric""" -type ImpactMetric implements Node { +"""A person who uses our app""" +type User implements Node { """The ID of an object""" id: ID! - """Charity ID that this impact metric belongs to""" - charity: Charity + """The users's Firebase ID (not Relay global ID, unlike the `id` field""" + userId: String + + """Users's background image""" + backgroundImage: BackgroundImage """ - Dollar amount (in micro USDs) required to achieve an instance of this ImpactMetric + A user's cause-specific impact for the cause they are currently supporting """ - dollarAmount: Int! + userImpact: UserImpact - """Markdown description of this ImpactMetric""" - description: String! + """Users's username""" + username: String - """ - Markdown. A shorter version of the description that answers "why this impact matters". - """ - whyValuableDescription: String! + """User's email""" + email: String - """ - Metric title. Should be placeable in a sentence. Example: "1 home visit" - """ - metricTitle: String! + """a unique user ID sent to video ad partner truex""" + truexId: String! + + """cause type for the user""" + cause: Cause + + """whether a user has completed 3 video ads in the last 24 hours""" + videoAdEligible: Boolean + + """ISO datetime string of when the user joined""" + joined: String """ - Impact action title. Should be a longer title with a verb as well as a noun. - Example: "Provide 1 visit from a community health worker" + Whether or not the user was created during this request. Helpful for a "get or create" mutation """ - impactTitle: String! + justCreated: Boolean - """Whether or not this GroupImpactMetric is still active""" - active: Boolean! -} + """User's current VC""" + vcCurrent: Int -"""inviting user""" -type InvitingUser { - """the name entered in invite""" - name: String! -} + """User's all time VC""" + vcAllTime: Int -input LogEmailVerifiedMutationInput { - userId: String! - clientMutationId: String -} + """User's all time tab count""" + tabs: Int -type LogEmailVerifiedMutationPayload { - user: User - clientMutationId: String -} + """User's tab count for today""" + tabsToday: Int -input LogReferralLinkClickInput { - userId: String! - clientMutationId: String -} + """Info about the user's day of most opened tabs""" + maxTabsDay: MaxTabsDay -type LogReferralLinkClickPayload { - success: Boolean! - clientMutationId: String -} + """User's vc""" + level: Int + + """If true, serve the new Tab V4 app.""" + v4BetaEnabled: Boolean + + """if true, user has viewed intro flow in v4""" + hasViewedIntroFlow: Boolean! + + """Remaing hearts until next level.""" + heartsUntilNextLevel: Int + + """User's total vc donated""" + vcDonatedAllTime: Int + + """People recruited by this user""" + recruits( + """Returns the items in the list that come after the specified cursor.""" + after: String + + """Returns the first n items from the list.""" + first: Int + + """Returns the items in the list that come before the specified cursor.""" + before: String + + """Returns the last n items from the list.""" + last: Int + startTime: String + endTime: String + ): UserRecruitsConnection + + """The number of users this user has recruited""" + numUsersRecruited: Int + + """User widgets""" + widgets( + """Returns the items in the list that come after the specified cursor.""" + after: String + + """Returns the first n items from the list.""" + first: Int + + """Returns the items in the list that come before the specified cursor.""" + before: String + + """Returns the last n items from the list.""" + last: Int + enabled: Boolean + ): WidgetConnection + + """User's active widget id""" + activeWidget: String + + """the current active mission for a user""" + currentMission: Mission + + """gets all the past missions for a user""" + pastMissions( + """Returns the items in the list that come after the specified cursor.""" + after: String + + """Returns the first n items from the list.""" + first: Int + + """Returns the items in the list that come before the specified cursor.""" + before: String + + """Returns the last n items from the list.""" + last: Int + ): MissionConnection + + """User's background option""" + backgroundOption: String + + """User's background custom image""" + customImage: String -input LogSearchInput { - """ - The user Relay global ID. Provide either this or `userId` for an existing user. - """ - userIdGlobal: String + """User's background color""" + backgroundColor: String """ - The actual user ID (not the Relay global). Provide either this or `userIdGlobal` for an existing user. + Whether this user was created by an existing user and then merged into the existing user """ - userId: String + mergedIntoExistingUser: Boolean - """The anonymous user ID. Provide this for an anonymous user.""" - anonUserId: String - source: String - causeId: String - searchEngineId: String - version: Int - clientMutationId: String -} + """User's all time search count""" + searches: Int -type LogSearchPayload { - user: User - success: Boolean - clientMutationId: String -} + """notifications for the v4 user to see""" + notifications: [notifications]! -input LogTabInput { - userId: String! - tabId: String - isV4: Boolean - clientMutationId: String -} + """User's search count for today""" + searchesToday: Int -type LogTabPayload { - user: User - clientMutationId: String -} + """Info about any search query rate-limiting""" + searchRateLimit: SearchRateLimit -input LogUserDataConsentInput { - userId: String! - consentString: String! - isGlobalConsent: Boolean! - clientMutationId: String -} + """Info about the user's day of most searches""" + maxSearchesDay: MaxSearchesDay -type LogUserDataConsentPayload { - success: Boolean! - clientMutationId: String -} + """Actions the user has taken during experiments""" + experimentActions: ExperimentActionsOutput + pendingMissionInvites: [PendingMissionInvite]! -input LogUserExperimentActionsInput { - userId: String! - experimentActions: ExperimentActions - clientMutationId: String -} + """whether a v4 user has been introduced to squads in the ui""" + hasSeenSquads: Boolean! -type LogUserExperimentActionsPayload { - user: User - clientMutationId: String -} + """feature values for this specific user""" + features: [Feature]! -enum LogUserRevenueAggregationOperationEnum { - MAX -} + """the User’s search engine""" + searchEngine: SearchEnginePersonalized -input LogUserRevenueInput { - userId: String! - revenue: Float + """whether to show the yahoo search prompt""" + showYahooPrompt: Boolean! - """A revenue value encoded because it is not available on the client side""" - encodedRevenue: EncodedRevenueValue - aggregationOperation: LogUserRevenueAggregationOperationEnum - dfpAdvertiserId: String - adUnitCode: String - tabId: String - adSize: String - isV4: Boolean - clientMutationId: String -} + """whether to show the SFAC extension prompt""" + showSfacExtensionPrompt: Boolean! -type LogUserRevenuePayload { - success: Boolean! - clientMutationId: String + """whether to show the SFAC icon (and activity ui element)""" + showSfacIcon: Boolean! + sfacActivityState: sfacActivityState! + + """whether or not the user has opted into searching for extra impact""" + yahooPaidSearchRewardOptIn: Boolean! } -input LogVideoAdCompleteInput { +"""a user's charity specific impact""" +type UserImpact { + """The ID of an object""" + id: ID! userId: String! - signatureArgumentString: String! - signature: String! - videoAdId: String! - truexAdId: String! - truexCreativeId: String! - clientMutationId: String -} + charityId: String! -type LogVideoAdCompletePayload { - success: Boolean! - user: User! - clientMutationId: String -} + """a users impact for a specific charity""" + userImpactMetric: Float! -"""Info about the user's day of most searches""" -type MaxSearchesDay { - """The day (datetime)the most searches occurred""" - date: String + """a users pending impact based on referrals""" + pendingUserReferralImpact: Float! - """The number of searches made on that day""" - numSearches: Int + """pending user referral count""" + pendingUserReferralCount: Float! + + """visits remaining until next recorded impact""" + visitsUntilNextImpact: Float! + + """enables a user to start accruing impact""" + confirmedImpact: Boolean! + + """flag that indicates if user has celebrated latest impact""" + hasClaimedLatestReward: Boolean! } """Info about the user's day of most opened tabs""" @@ -945,14 +974,40 @@ type MaxTabsDay { numTabs: Int } -input MergeIntoExistingUserInput { - userId: String! - clientMutationId: String +"""A connection to a list of items.""" +type UserRecruitsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [UserRecruitsEdge] + + """The count of users recruited (signed up)""" + totalRecruits: Int + + """The count of users recruited who remained active for one day or more""" + recruitsActiveForAtLeastOneDay: Int + + """The count of users recruited who have opened one tab or more""" + recruitsWithAtLeastOneTab: Int } -type MergeIntoExistingUserPayload { - success: Boolean! - clientMutationId: String +"""An edge in a connection.""" +type UserRecruitsEdge { + """The item at the end of the edge""" + node: UserRecruits + + """A cursor for use in pagination""" + cursor: String! +} + +"""Info about a user recruited by a referring user""" +type UserRecruits { + """The ID of an object""" + id: ID! + + """ISO datetime string of when the recruited user joined""" + recruitedAt: String } """A goal that Tabbers complete with a group of friends""" @@ -993,24 +1048,6 @@ type Mission { completed: String } -"""A connection to a list of items.""" -type MissionConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [MissionEdge] -} - -"""An edge in a connection.""" -type MissionEdge { - """The item at the end of the edge""" - node: Mission - - """A cursor for use in pagination""" - cursor: String! -} - """whether a user has accepted rejected or is pending invitation""" enum missionStatus { pending @@ -1018,179 +1055,148 @@ enum missionStatus { completed } -type Mutation { - logTab(input: LogTabInput!): LogTabPayload - updateImpact(input: UpdateImpactInput!): UpdateImpactPayload - createInvitedUsers(input: CreateInvitedUsersInput!): CreateInvitedUsersPayload - createSquadInvites(input: CreateSquadInvitesInput!): CreateSquadInvitesPayload - logSearch(input: LogSearchInput!): LogSearchPayload - logUserRevenue(input: LogUserRevenueInput!): LogUserRevenuePayload - logUserDataConsent(input: LogUserDataConsentInput!): LogUserDataConsentPayload - donateVc(input: DonateVcInput!): DonateVcPayload - mergeIntoExistingUser(input: MergeIntoExistingUserInput!): MergeIntoExistingUserPayload - logEmailVerified(input: LogEmailVerifiedMutationInput!): LogEmailVerifiedMutationPayload - logReferralLinkClick(input: LogReferralLinkClickInput!): LogReferralLinkClickPayload - setUserBkgImage(input: SetUserBkgImageInput!): SetUserBkgImagePayload - setUserBkgColor(input: SetUserBkgColorInput!): SetUserBkgColorPayload - setUserBkgCustomImage(input: SetUserBkgCustomImageInput!): SetUserBkgCustomImagePayload - setUserBkgDailyImage(input: SetUserBkgDailyImageInput!): SetUserBkgDailyImagePayload - updateWidgetData(input: UpdateWidgetDataInput!): UpdateWidgetDataPayload - updateWidgetVisibility(input: UpdateWidgetVisibilityInput!): UpdateWidgetVisibilityPayload - updateWidgetEnabled(input: UpdateWidgetEnabledInput!): UpdateWidgetEnabledPayload - updateWidgetConfig(input: UpdateWidgetConfigInput!): UpdateWidgetConfigPayload - setUserActiveWidget(input: SetUserActiveWidgetInput!): SetUserActiveWidgetPayload - createNewUser(input: CreateNewUserInput!): CreateNewUserPayload - createNewMission(input: CreateNewMissionInput!): CreateNewMissionPayload - setUsername(input: SetUsernameInput!): SetUsernamePayload - setEmail(input: SetEmailInput!): SetEmailPayload - updateUserExperimentGroups(input: UpdateUserExperimentGroupsInput!): UpdateUserExperimentGroupsPayload - logUserExperimentActions(input: LogUserExperimentActionsInput!): LogUserExperimentActionsPayload - setV4Beta(input: SetV4BetaInput!): SetV4BetaPayload - setHasViewedIntroFlow(input: SetHasViewedIntroFlowInput!): SetHasViewedIntroFlowPayload - setUserCause(input: SetUserCauseInput!): SetUserCausePayload - deleteUser(input: DeleteUserInput!): DeleteUserPayload - squadInviteResponse(input: SquadInviteResponseInput!): SquadInviteResponsePayload - updateMissionNotification(input: UpdateMissionNotificationInput!): UpdateMissionNotificationPayload - setHasSeenSquads(input: SetHasSeenSquadsInput!): SetHasSeenSquadsPayload - setHasSeenCompletedMission(input: SetHasSeenCompletedMissionInput!): SetHasSeenCompletedMissionPayload - restartMission(input: RestartMissionInput!): RestartMissionPayload - createVideoAdLog(input: CreateVideoAdLogInput!): CreateVideoAdLogPayload - logVideoAdComplete(input: LogVideoAdCompleteInput!): LogVideoAdCompletePayload - setYahooSearchOptIn(input: SetYahooSearchOptInInput!): SetYahooSearchOptInPayload - setUserSearchEngine(input: SetUserSearchEngineInput!): SetUserSearchEnginePayload - createSearchEnginePromptLog(input: CreateSearchEnginePromptLogInput!): CreateSearchEnginePromptLogPayload - createSfacExtensionPromptResponse(input: CreateSfacExtensionPromptResponseInput!): CreateSfacExtensionPromptResponsePayload - createUserExperiment(input: CreateUserExperimentInput!): CreateUserExperimentPayload -} +"""an individual's stats for a mission""" +type SquadMemberInfo { + """Users's username if they have joined TFAC""" + username: String + + """Users's invited email if they have not joined TFAC""" + invitedEmail: String + status: squadAcceptedStatus! + + """the longest tab streak in days so far""" + longestTabStreak: Int! + + """the current tab streak in days so far""" + currentTabStreak: Int! + + """the most tabs in a single day""" + missionMaxTabsDay: Int! -"""An object with an ID""" -interface Node { - """The id of the object.""" - id: ID! -} + """the current tabs today""" + missionCurrentTabsDay: Int! -"""user notifications to show on v4""" -type notifications { - """the kind of notification it is""" - code: String + """users tab contribution""" + tabs: Int! } -"""cause specific UI content around onboarding""" -type OnboardingUICopy { - """the steps array in onboarding""" - steps: [onboardingUIStep]! - - """ - markdown string shown when prompting the user to open their first tab, currently info about cat treats - """ - firstTabIntroDescription: String! +"""whether a user has accepted rejected or is pending invitation""" +enum squadAcceptedStatus { + pending + accepted + rejected } -"""ui content for each onboarding step""" -type onboardingUIStep { - """markdown title for onboarding step""" - title: String! +"""persistant awards calculated at end of mission""" +type EndOfMissionAward { + """users ID""" + user: String! - """markdown subtitle for onboarding step""" - subtitle: String! + """the string name of the particular award""" + awardType: String! - """name of image to show""" - imgName: String! + """the numerical stat for the award, such as number of tabs""" + unit: Int! } -"""Information about pagination in a connection.""" -type PageInfo { - """When paginating forwards, are there more items?""" - hasNextPage: Boolean! +"""A connection to a list of items.""" +type MissionConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! - """When paginating backwards, are there more items?""" - hasPreviousPage: Boolean! + """A list of edges.""" + edges: [MissionEdge] +} - """When paginating backwards, the cursor to continue.""" - startCursor: String +"""An edge in a connection.""" +type MissionEdge { + """The item at the end of the edge""" + node: Mission - """When paginating forwards, the cursor to continue.""" - endCursor: String + """A cursor for use in pagination""" + cursor: String! } -"""pending mission invites for user""" -type PendingMissionInvite { - """the mission id of the squad invite""" - missionId: String! - invitingUser: InvitingUser -} +"""user notifications to show on v4""" +type notifications { + """the kind of notification it is""" + code: String -type Query { - """Fetches an object given its ID""" - node( - """The ID of an object""" - id: ID! - ): Node - app: App - user(userId: String!): User - userImpact(userId: String!, charityId: String!): UserImpact + """ + the variation of the notification given to this user (e.g. for A/B testing) + """ + variation: String! } -input ReferralData { - referringUser: String - referringChannel: String -} +"""Info about any rate-limiting for VC earned from search queries""" +type SearchRateLimit { + """ + Whether we are currently rate-limiting the user's VC earned from searches + """ + limitReached: Boolean + reason: SearchRateLimitReason -input RestartMissionInput { - userId: String! - missionId: String! - clientMutationId: String + """Whether we should present the user with a CAPTCHA""" + checkIfHuman: Boolean } -type RestartMissionPayload { - """the current active mission for a user""" - currentMission: Mission - clientMutationId: String +"""Why we are rate-limiting the user's VC earned from searches""" +enum SearchRateLimitReason { + NONE + ONE_MINUTE_MAX + FIVE_MINUTE_MAX + DAILY_MAX } -"""all important data for a search engine.""" -type SearchEngine implements Node { - """Engine's id""" - engineId: String! - - """Name of the Search Engine""" - name: String! - - """what order to display the search engine in a list""" - rank: Int! +"""Info about the user's day of most searches""" +type MaxSearchesDay { + """The day (datetime)the most searches occurred""" + date: String - """Whether or not the user can earn extra impact with this Search Engine""" - isCharitable: Boolean! + """The number of searches made on that day""" + numSearches: Int +} - """Display string to display in the search bar""" - inputPrompt: String! +"""The actions a user has taken in an experiment""" +type ExperimentActionsOutput { + searchIntro: ExperimentActionSearchIntro + referralNotification: ExperimentActionReferralNotification +} - """The ID of an object""" - id: ID! +"""Action taken in response to the "search intro" experiment.""" +enum ExperimentActionSearchIntro { + NONE + DISMISS + CLICK +} - """ - A search destination URL, with a {searchTerms} placeholder for the client to - replace. Use `user.searchEngine` if the user is authenticated. - """ - searchUrl: String! +"""Action taken in response to the "referral notification" experiment.""" +enum ExperimentActionReferralNotification { + NONE + DISMISS + CLICK } -"""A connection to a list of items.""" -type SearchEngineConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! +"""pending mission invites for user""" +type PendingMissionInvite { + """the mission id of the squad invite""" + missionId: String! + invitingUser: InvitingUser +} - """A list of edges.""" - edges: [SearchEngineEdge] +"""inviting user""" +type InvitingUser { + """the name entered in invite""" + name: String! } -"""An edge in a connection.""" -type SearchEngineEdge { - """The item at the end of the edge""" - node: SearchEngine +"""Feature name and variation value pair applicable to a user.""" +type Feature { + """Name of the Feature""" + featureName: String! - """A cursor for use in pagination""" - cursor: String! + """the value of the variation for this specific user""" + variation: String! } """ @@ -1213,9 +1219,7 @@ type SearchEnginePersonalized implements Node { inputPrompt: String! """ - Use this for the user's search behavior. A search destination URL, with a - {searchTerms} placeholder for the client to replace. The URL might be - personalized based on the user. + Use this for the user's search behavior. A search destination URL, with a {searchTerms} placeholder for the client to replace. The URL might be personalized based on the user. """ searchUrlPersonalized: String! @@ -1223,317 +1227,302 @@ type SearchEnginePersonalized implements Node { id: ID! } -"""Info about any rate-limiting for VC earned from search queries""" -type SearchRateLimit { - """ - Whether we are currently rate-limiting the user's VC earned from searches - """ - limitReached: Boolean - reason: SearchRateLimitReason - - """Whether we should present the user with a CAPTCHA""" - checkIfHuman: Boolean -} - -"""Why we are rate-limiting the user's VC earned from searches""" -enum SearchRateLimitReason { - NONE - ONE_MINUTE_MAX - FIVE_MINUTE_MAX - DAILY_MAX +"""what mode in which to show SFAC searches UI""" +enum sfacActivityState { + new + active + inactive } -input SetEmailInput { - userId: String! - clientMutationId: String +type Mutation { + logTab(input: LogTabInput!): LogTabPayload + updateImpact(input: UpdateImpactInput!): UpdateImpactPayload + createInvitedUsers(input: CreateInvitedUsersInput!): CreateInvitedUsersPayload + createSquadInvites(input: CreateSquadInvitesInput!): CreateSquadInvitesPayload + logSearch(input: LogSearchInput!): LogSearchPayload + logUserRevenue(input: LogUserRevenueInput!): LogUserRevenuePayload + logUserDataConsent(input: LogUserDataConsentInput!): LogUserDataConsentPayload + donateVc(input: DonateVcInput!): DonateVcPayload + mergeIntoExistingUser(input: MergeIntoExistingUserInput!): MergeIntoExistingUserPayload + logEmailVerified(input: LogEmailVerifiedMutationInput!): LogEmailVerifiedMutationPayload + logReferralLinkClick(input: LogReferralLinkClickInput!): LogReferralLinkClickPayload + setUserBkgImage(input: SetUserBkgImageInput!): SetUserBkgImagePayload + setUserBkgColor(input: SetUserBkgColorInput!): SetUserBkgColorPayload + setUserBkgCustomImage(input: SetUserBkgCustomImageInput!): SetUserBkgCustomImagePayload + setUserBkgDailyImage(input: SetUserBkgDailyImageInput!): SetUserBkgDailyImagePayload + updateWidgetData(input: UpdateWidgetDataInput!): UpdateWidgetDataPayload + updateWidgetVisibility(input: UpdateWidgetVisibilityInput!): UpdateWidgetVisibilityPayload + updateWidgetEnabled(input: UpdateWidgetEnabledInput!): UpdateWidgetEnabledPayload + updateWidgetConfig(input: UpdateWidgetConfigInput!): UpdateWidgetConfigPayload + setUserActiveWidget(input: SetUserActiveWidgetInput!): SetUserActiveWidgetPayload + createNewUser(input: CreateNewUserInput!): CreateNewUserPayload + createNewMission(input: CreateNewMissionInput!): CreateNewMissionPayload + setUsername(input: SetUsernameInput!): SetUsernamePayload + setEmail(input: SetEmailInput!): SetEmailPayload + updateUserExperimentGroups(input: UpdateUserExperimentGroupsInput!): UpdateUserExperimentGroupsPayload + logUserExperimentActions(input: LogUserExperimentActionsInput!): LogUserExperimentActionsPayload + setV4Beta(input: SetV4BetaInput!): SetV4BetaPayload + setHasViewedIntroFlow(input: SetHasViewedIntroFlowInput!): SetHasViewedIntroFlowPayload + setUserCause(input: SetUserCauseInput!): SetUserCausePayload + deleteUser(input: DeleteUserInput!): DeleteUserPayload + squadInviteResponse(input: SquadInviteResponseInput!): SquadInviteResponsePayload + updateMissionNotification(input: UpdateMissionNotificationInput!): UpdateMissionNotificationPayload + setHasSeenSquads(input: SetHasSeenSquadsInput!): SetHasSeenSquadsPayload + setHasSeenCompletedMission(input: SetHasSeenCompletedMissionInput!): SetHasSeenCompletedMissionPayload + restartMission(input: RestartMissionInput!): RestartMissionPayload + createVideoAdLog(input: CreateVideoAdLogInput!): CreateVideoAdLogPayload + logVideoAdComplete(input: LogVideoAdCompleteInput!): LogVideoAdCompletePayload + setYahooSearchOptIn(input: SetYahooSearchOptInInput!): SetYahooSearchOptInPayload + setUserSearchEngine(input: SetUserSearchEngineInput!): SetUserSearchEnginePayload + createSearchEnginePromptLog(input: CreateSearchEnginePromptLogInput!): CreateSearchEnginePromptLogPayload + createSfacExtensionPromptResponse(input: CreateSfacExtensionPromptResponseInput!): CreateSfacExtensionPromptResponsePayload + createUserExperiment(input: CreateUserExperimentInput!): CreateUserExperimentPayload } -type SetEmailPayload { +type LogTabPayload { user: User - errors: [CustomError] clientMutationId: String } -input SetHasSeenCompletedMissionInput { +input LogTabInput { userId: String! - missionId: String! + tabId: String + isV4: Boolean clientMutationId: String } -type SetHasSeenCompletedMissionPayload { - success: Boolean! +type UpdateImpactPayload { + userImpact: UserImpact clientMutationId: String } -input SetHasSeenSquadsInput { +input UpdateImpactInput { userId: String! + charityId: String + logImpact: Boolean + claimPendingUserReferralImpact: Boolean + confirmImpact: Boolean + claimLatestReward: Boolean clientMutationId: String } -type SetHasSeenSquadsPayload { - user: User +type CreateInvitedUsersPayload { + successfulEmailAddresses: [successfulEmailAddresses] + failedEmailAddresses: [failedEmailAddresses] clientMutationId: String } -input SetHasViewedIntroFlowInput { - userId: String! - enabled: Boolean! - clientMutationId: String +type successfulEmailAddresses { + email: String } -type SetHasViewedIntroFlowPayload { - user: User - clientMutationId: String +type failedEmailAddresses { + email: String + error: String } -input SetUserActiveWidgetInput { - userId: String! - widgetId: String! +input CreateInvitedUsersInput { + inviterId: String! + invitedEmails: [String]! + inviterName: String + inviterMessage: String clientMutationId: String } -type SetUserActiveWidgetPayload { - user: User +type CreateSquadInvitesPayload { + """the current active mission for a user""" + currentMission: Mission clientMutationId: String } -input SetUserBkgColorInput { - userId: String! - color: String! +input CreateSquadInvitesInput { + inviterId: String! + invitedEmails: [String]! + inviterName: String! + inviterMessage: String clientMutationId: String } -type SetUserBkgColorPayload { +type LogSearchPayload { user: User + success: Boolean clientMutationId: String } -input SetUserBkgCustomImageInput { - userId: String! - image: String! +input LogSearchInput { + """ + The user Relay global ID. Provide either this or `userId` for an existing user. + """ + userIdGlobal: String + + """ + The actual user ID (not the Relay global). Provide either this or `userIdGlobal` for an existing user. + """ + userId: String + + """The anonymous user ID. Provide this for an anonymous user.""" + anonUserId: String + source: String + causeId: String + searchEngineId: String + version: Int clientMutationId: String } -type SetUserBkgCustomImagePayload { - user: User +type LogUserRevenuePayload { + success: Boolean! clientMutationId: String } -input SetUserBkgDailyImageInput { +input LogUserRevenueInput { userId: String! - category: String - clientMutationId: String -} + revenue: Float -type SetUserBkgDailyImagePayload { - user: User + """A revenue value encoded because it is not available on the client side""" + encodedRevenue: EncodedRevenueValue + aggregationOperation: LogUserRevenueAggregationOperationEnum + dfpAdvertiserId: String + adUnitCode: String + tabId: String + adSize: String + isV4: Boolean clientMutationId: String } -input SetUserBkgImageInput { - userId: String! - imageId: String! - clientMutationId: String +"""An object representing a single revenue value""" +input EncodedRevenueValue { + encodingType: EncodedRevenueValueTypeEnum! + + """ + A string that we can decode to a revenue value (float) using the "encodingType" method + """ + encodedValue: String! + adSize: String } -type SetUserBkgImagePayload { - user: User - clientMutationId: String +""" +The type of transformation we should use to resolve the object into a revenue value +""" +enum EncodedRevenueValueTypeEnum { + AMAZON_CPM } -input SetUserCauseInput { - userId: String! - causeId: String! - clientMutationId: String +""" +The operation to use to resolve multiple values into a final revenue value. We currently only support "MAX". +""" +enum LogUserRevenueAggregationOperationEnum { + MAX } -type SetUserCausePayload { - user: User +type LogUserDataConsentPayload { + success: Boolean! clientMutationId: String } -input SetUsernameInput { +input LogUserDataConsentInput { userId: String! - username: String! + consentString: String! + isGlobalConsent: Boolean! clientMutationId: String } -type SetUsernamePayload { +type DonateVcPayload { user: User errors: [CustomError] clientMutationId: String } -input SetUserSearchEngineInput { - userId: String! - searchEngine: String! - clientMutationId: String -} +"""For expected errors, such as during form validation""" +type CustomError { + """The error code""" + code: String -type SetUserSearchEnginePayload { - user: User - clientMutationId: String + """The error message""" + message: String } -input SetV4BetaInput { +input DonateVcInput { userId: String! - enabled: Boolean! + charityId: String! + vc: Int! clientMutationId: String } -type SetV4BetaPayload { - user: User +type MergeIntoExistingUserPayload { + success: Boolean! clientMutationId: String } -input SetYahooSearchOptInInput { +input MergeIntoExistingUserInput { userId: String! - optIn: Boolean! clientMutationId: String } -type SetYahooSearchOptInPayload { +type LogEmailVerifiedMutationPayload { user: User clientMutationId: String } -"""what mode in which to show SFAC searches UI""" -enum sfacActivityState { - new - active - inactive -} - -"""cause specific UI content around sharing""" -type SharingUICopy { - """markdown for modal title""" - title: String! - - """markdown for modal subtitle""" - subtitle: String! - - """ - value to use for img switch statement on frontend, probably ‘cats’ or ‘seas’ - """ - imgCategory: String! - - """Image to use in email invite dialog""" - shareImage: String! - - """Image shown after email invite sent""" - sentImage: String! - - """copy for reddit button""" - redditButtonTitle: String! - - """copy for facebook button""" - facebookButtonTitle: String! - - """copy for twitter button""" - twitterButtonTitle: String! - - """copy for tumblr button""" - tumblrTitle: String! - - """copy for tumblr caption""" - tumblrCaption: String! -} - -"""whether a user has accepted rejected or is pending invitation""" -enum squadAcceptedStatus { - pending - accepted - rejected -} - -input SquadInviteResponseInput { +input LogEmailVerifiedMutationInput { userId: String! - missionId: String! - accepted: Boolean! clientMutationId: String } -type SquadInviteResponsePayload { - """the current active mission for a user""" - currentMission: Mission +type LogReferralLinkClickPayload { + success: Boolean! clientMutationId: String } -"""an individual's stats for a mission""" -type SquadMemberInfo { - """Users's username if they have joined TFAC""" - username: String - - """Users's invited email if they have not joined TFAC""" - invitedEmail: String - status: squadAcceptedStatus! - - """the longest tab streak in days so far""" - longestTabStreak: Int! - - """the current tab streak in days so far""" - currentTabStreak: Int! - - """the most tabs in a single day""" - missionMaxTabsDay: Int! - - """the current tabs today""" - missionCurrentTabsDay: Int! - - """users tab contribution""" - tabs: Int! +input LogReferralLinkClickInput { + userId: String! + clientMutationId: String } -type successfulEmailAddresses { - email: String +type SetUserBkgImagePayload { + user: User + clientMutationId: String } -input UpdateImpactInput { +input SetUserBkgImageInput { userId: String! - charityId: String - logImpact: Boolean - claimPendingUserReferralImpact: Boolean - confirmImpact: Boolean - claimLatestReward: Boolean + imageId: String! clientMutationId: String } -type UpdateImpactPayload { - userImpact: UserImpact +type SetUserBkgColorPayload { + user: User clientMutationId: String } -input UpdateMissionNotificationInput { +input SetUserBkgColorInput { userId: String! - missionId: String! - action: String! + color: String! clientMutationId: String } -type UpdateMissionNotificationPayload { - success: Boolean! +type SetUserBkgCustomImagePayload { + user: User clientMutationId: String } -input UpdateUserExperimentGroupsInput { +input SetUserBkgCustomImageInput { userId: String! - experimentGroups: ExperimentGroups + image: String! clientMutationId: String } -type UpdateUserExperimentGroupsPayload { +type SetUserBkgDailyImagePayload { user: User clientMutationId: String } -input UpdateWidgetConfigInput { +input SetUserBkgDailyImageInput { userId: String! - widgetId: String! - config: String! + category: String clientMutationId: String } -type UpdateWidgetConfigPayload { +type UpdateWidgetDataPayload { widget: Widget clientMutationId: String } @@ -1545,15 +1534,15 @@ input UpdateWidgetDataInput { clientMutationId: String } -type UpdateWidgetDataPayload { +type UpdateWidgetVisibilityPayload { widget: Widget clientMutationId: String } -input UpdateWidgetEnabledInput { +input UpdateWidgetVisibilityInput { userId: String! widgetId: String! - enabled: Boolean! + visible: Boolean! clientMutationId: String } @@ -1562,217 +1551,291 @@ type UpdateWidgetEnabledPayload { clientMutationId: String } -input UpdateWidgetVisibilityInput { +input UpdateWidgetEnabledInput { userId: String! widgetId: String! - visible: Boolean! + enabled: Boolean! clientMutationId: String } -type UpdateWidgetVisibilityPayload { +type UpdateWidgetConfigPayload { widget: Widget clientMutationId: String } -"""A person who uses our app""" -type User implements Node { - """The ID of an object""" - id: ID! - - """The users's Firebase ID (not Relay global ID, unlike the `id` field""" - userId: String +input UpdateWidgetConfigInput { + userId: String! + widgetId: String! + config: String! + clientMutationId: String +} - """Users's background image""" - backgroundImage: BackgroundImage +type SetUserActiveWidgetPayload { + user: User + clientMutationId: String +} - """ - A user's cause-specific impact for the cause they are currently supporting - """ - userImpact: UserImpact +input SetUserActiveWidgetInput { + userId: String! + widgetId: String! + clientMutationId: String +} - """Users's username""" - username: String +type CreateNewUserPayload { + user: User + clientMutationId: String +} - """User's email""" +input CreateNewUserInput { + userId: String! email: String + referralData: ReferralData + experimentGroups: ExperimentGroups + extensionInstallId: String + extensionInstallTimeApprox: String + v4BetaEnabled: Boolean + missionId: String + causeId: String + clientMutationId: String +} - """a unique user ID sent to video ad partner truex""" - truexId: String! - - """cause type for the user""" - cause: Cause - - """whether a user has completed 3 video ads in the last 24 hours""" - videoAdEligible: Boolean - - """ISO datetime string of when the user joined""" - joined: String - justCreated: Boolean - - """User's current VC""" - vcCurrent: Int - - """User's all time VC""" - vcAllTime: Int - - """User's all time tab count""" - tabs: Int - - """User's tab count for today""" - tabsToday: Int - - """Info about the user's day of most opened tabs""" - maxTabsDay: MaxTabsDay - - """User's vc""" - level: Int +input ReferralData { + referringUser: String + referringChannel: String +} - """If true, serve the new Tab V4 app.""" - v4BetaEnabled: Boolean +"""The experimental groups to which the user is assigned""" +input ExperimentGroups { + anonSignIn: ExperimentGroupAnonSignIn + variousAdSizes: ExperimentGroupVariousAdSizes + thirdAd: ExperimentGroupThirdAd + oneAdForNewUsers: ExperimentGroupOneAdForNewUsers + adExplanation: ExperimentGroupAdExplanation + searchIntro: ExperimentGroupSearchIntro + referralNotification: ExperimentGroupReferralNotification +} - """if true, user has viewed intro flow in v4""" - hasViewedIntroFlow: Boolean! +"""The test of allowing anonymous user authentication""" +enum ExperimentGroupAnonSignIn { + NONE + AUTHED_USER_ONLY + ANONYMOUS_ALLOWED +} - """Remaing hearts until next level.""" - heartsUntilNextLevel: Int +"""The test of enabling many different ad sizes""" +enum ExperimentGroupVariousAdSizes { + NONE + STANDARD + VARIOUS +} - """User's total vc donated""" - vcDonatedAllTime: Int +"""The test of enabling a third ad""" +enum ExperimentGroupThirdAd { + NONE + TWO_ADS + THREE_ADS +} - """People recruited by this user""" - recruits(after: String, first: Int, before: String, last: Int, startTime: String, endTime: String): UserRecruitsConnection +"""The test of showing only one ad to new users""" +enum ExperimentGroupOneAdForNewUsers { + NONE + DEFAULT + ONE_AD_AT_FIRST +} - """The number of users this user has recruited""" - numUsersRecruited: Int +"""The test of showing an explanation of why there are ads""" +enum ExperimentGroupAdExplanation { + NONE + DEFAULT + SHOW_EXPLANATION +} - """User widgets""" - widgets(after: String, first: Int, before: String, last: Int, enabled: Boolean): WidgetConnection +"""The test of showing an introduction message to Search for a Cause""" +enum ExperimentGroupSearchIntro { + NONE + NO_INTRO + INTRO_A + INTRO_HOMEPAGE +} - """User's active widget id""" - activeWidget: String +"""The test of showing a notification to ask users to recruit friends""" +enum ExperimentGroupReferralNotification { + NONE + NO_NOTIFICATION + COPY_A + COPY_B + COPY_C + COPY_D + COPY_E +} +type CreateNewMissionPayload { """the current active mission for a user""" currentMission: Mission + clientMutationId: String +} - """gets all the past missions for a user""" - pastMissions(after: String, first: Int, before: String, last: Int): MissionConnection - - """User's background option""" - backgroundOption: String - - """User's background custom image""" - customImage: String - - """User's background color""" - backgroundColor: String - - """ - Whether this user was created by an existing user and then merged into the existing user - """ - mergedIntoExistingUser: Boolean - - """User's all time search count""" - searches: Int +input CreateNewMissionInput { + userId: String! + squadName: String! + clientMutationId: String +} - """notifications for the v4 user to see""" - notifications: [notifications]! +type SetUsernamePayload { + user: User + errors: [CustomError] + clientMutationId: String +} - """User's search count for today""" - searchesToday: Int +input SetUsernameInput { + userId: String! + username: String! + clientMutationId: String +} - """Info about any search query rate-limiting""" - searchRateLimit: SearchRateLimit +type SetEmailPayload { + user: User + errors: [CustomError] + clientMutationId: String +} - """Info about the user's day of most searches""" - maxSearchesDay: MaxSearchesDay +input SetEmailInput { + userId: String! + clientMutationId: String +} - """Actions the user has taken during experiments""" - experimentActions: ExperimentActionsOutput - pendingMissionInvites: [PendingMissionInvite]! +type UpdateUserExperimentGroupsPayload { + user: User + clientMutationId: String +} - """whether a v4 user has been introduced to squads in the ui""" - hasSeenSquads: Boolean! +input UpdateUserExperimentGroupsInput { + userId: String! + experimentGroups: ExperimentGroups + clientMutationId: String +} - """feature values for this specific user""" - features: [Feature]! +type LogUserExperimentActionsPayload { + user: User + clientMutationId: String +} - """the User’s search engine""" - searchEngine: SearchEnginePersonalized +input LogUserExperimentActionsInput { + userId: String! + experimentActions: ExperimentActions + clientMutationId: String +} - """whether to show the yahoo search prompt""" - showYahooPrompt: Boolean! +"""The actions a user may take in an experiment""" +input ExperimentActions { + searchIntro: ExperimentActionSearchIntro + referralNotification: ExperimentActionReferralNotification +} - """whether to show the SFAC extension prompt""" - showSfacExtensionPrompt: Boolean! +type SetV4BetaPayload { + user: User + clientMutationId: String +} - """whether to show the SFAC icon (and activity ui element)""" - showSfacIcon: Boolean! - sfacActivityState: sfacActivityState! +input SetV4BetaInput { + userId: String! + enabled: Boolean! + clientMutationId: String +} - """whether or not the user has opted into searching for extra impact""" - yahooPaidSearchRewardOptIn: Boolean! +type SetHasViewedIntroFlowPayload { + user: User + clientMutationId: String } -"""a user's charity specific impact""" -type UserImpact { - """The ID of an object""" - id: ID! +input SetHasViewedIntroFlowInput { userId: String! - charityId: String! + enabled: Boolean! + clientMutationId: String +} - """a users impact for a specific charity""" - userImpactMetric: Float! +type SetUserCausePayload { + user: User + clientMutationId: String +} - """a users pending impact based on referrals""" - pendingUserReferralImpact: Float! +input SetUserCauseInput { + userId: String! + causeId: String! + clientMutationId: String +} - """pending user referral count""" - pendingUserReferralCount: Float! +type DeleteUserPayload { + success: Boolean! + clientMutationId: String +} - """visits remaining until next recorded impact""" - visitsUntilNextImpact: Float! +input DeleteUserInput { + userId: String! + clientMutationId: String +} - """enables a user to start accruing impact""" - confirmedImpact: Boolean! +type SquadInviteResponsePayload { + """the current active mission for a user""" + currentMission: Mission + clientMutationId: String +} - """flag that indicates if user has celebrated latest impact""" - hasClaimedLatestReward: Boolean! +input SquadInviteResponseInput { + userId: String! + missionId: String! + accepted: Boolean! + clientMutationId: String } -"""Info about a user recruited by a referring user""" -type UserRecruits { - """The ID of an object""" - id: ID! +type UpdateMissionNotificationPayload { + success: Boolean! + clientMutationId: String +} - """ISO datetime string of when the recruited user joined""" - recruitedAt: String +input UpdateMissionNotificationInput { + userId: String! + missionId: String! + action: String! + clientMutationId: String } -"""A connection to a list of items.""" -type UserRecruitsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! +type SetHasSeenSquadsPayload { + user: User + clientMutationId: String +} - """A list of edges.""" - edges: [UserRecruitsEdge] +input SetHasSeenSquadsInput { + userId: String! + clientMutationId: String +} - """The count of users recruited (signed up)""" - totalRecruits: Int +type SetHasSeenCompletedMissionPayload { + success: Boolean! + clientMutationId: String +} - """The count of users recruited who remained active for one day or more""" - recruitsActiveForAtLeastOneDay: Int +input SetHasSeenCompletedMissionInput { + userId: String! + missionId: String! + clientMutationId: String +} - """The count of users recruited who have opened one tab or more""" - recruitsWithAtLeastOneTab: Int +type RestartMissionPayload { + """the current active mission for a user""" + currentMission: Mission + clientMutationId: String } -"""An edge in a connection.""" -type UserRecruitsEdge { - """The item at the end of the edge""" - node: UserRecruits +input RestartMissionInput { + userId: String! + missionId: String! + clientMutationId: String +} - """A cursor for use in pagination""" - cursor: String! +type CreateVideoAdLogPayload { + VideoAdLog: VideoAdLog + clientMutationId: String } """Video Ad Log type""" @@ -1781,50 +1844,83 @@ type VideoAdLog implements Node { id: ID! } -"""App widget""" -type Widget implements Node { - """The ID of an object""" - id: ID! - - """Widget display name""" - name: String +input CreateVideoAdLogInput { + userId: String! + clientMutationId: String +} - """Widget type""" - type: String +type LogVideoAdCompletePayload { + success: Boolean! + user: User! + clientMutationId: String +} - """Widget icon""" - icon: String +input LogVideoAdCompleteInput { + userId: String! + signatureArgumentString: String! + signature: String! + videoAdId: String! + truexAdId: String! + truexCreativeId: String! + clientMutationId: String +} - """The Widget enabled state""" - enabled: Boolean +type SetYahooSearchOptInPayload { + user: User + clientMutationId: String +} - """The Widget visible state""" - visible: Boolean +input SetYahooSearchOptInInput { + userId: String! + optIn: Boolean! + clientMutationId: String +} - """Widget data.""" - data: String +type SetUserSearchEnginePayload { + user: User + clientMutationId: String +} - """Widget user specific configuration.""" - config: String +input SetUserSearchEngineInput { + userId: String! + searchEngine: String! + clientMutationId: String +} - """Widget general configuration.""" - settings: String +type CreateSearchEnginePromptLogPayload { + success: Boolean! + user: User + clientMutationId: String } -"""A connection to a list of items.""" -type WidgetConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! +input CreateSearchEnginePromptLogInput { + userId: String! + searchEnginePrompted: String! + switched: Boolean! + clientMutationId: String +} - """A list of edges.""" - edges: [WidgetEdge] +type CreateSfacExtensionPromptResponsePayload { + user: User + clientMutationId: String } -"""An edge in a connection.""" -type WidgetEdge { - """The item at the end of the edge""" - node: Widget +input CreateSfacExtensionPromptResponseInput { + userId: String! + browser: String! + accepted: Boolean! + clientMutationId: String +} - """A cursor for use in pagination""" - cursor: String! +type CreateUserExperimentPayload { + success: Boolean! + clientMutationId: String } + +input CreateUserExperimentInput { + userId: String! + experimentId: String! + variationId: Int! + variationValueStr: String + clientMutationId: String +} \ No newline at end of file