Skip to content

Commit

Permalink
feat: add earnedByCurrentUser prop and use it at frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
juliano-quatrin-nunes committed Jan 17, 2025
1 parent a1c0f7f commit c287abe
Show file tree
Hide file tree
Showing 14 changed files with 67 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ def resolve
current_user = context[:current_user]
badges = Gamification::BadgeReadModel.includes(:user_badges)

return badges unless current_user

earned_badge_ids = Gamification::UserBadgeReadModel
.where(user_id: current_user.id)
.where(badgeable_type: "Gamification::BadgeReadModel")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ def resolve
current_user = context[:current_user]
badges = Gamification::SpecialBadgeReadModel.includes(:user_badges)

return badges unless current_user

earned_badge_ids = Gamification::UserBadgeReadModel
.where(user_id: current_user.id)
.where(badgeable_type: "Gamification::SpecialBadgeReadModel")
Expand Down
16 changes: 8 additions & 8 deletions apps/govquests-api/rails_app/app/graphql/types/badge_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ class BadgeType < Types::BaseObject
field :id, ID, null: false, method: :badge_id
field :display_data, Types::BadgeDisplayDataType, null: false
field :badgeable, Types::BadgeableUnion, null: true
field :current_user_badges, [Types::UserBadgeType], null: false
field :user_badges, [Types::UserBadgeType], null: false
field :earned_by_current_user, Boolean, null: false

def current_user_badges
Loaders::AssociationLoader.for(
Gamification::BadgeReadModel,
:user_badges
).load(object).then do |user_badges|
user_badges.where(user_id: context[:current_user].id)
end
def user_badges
object.user_badges.where(user: context[:current_user])
end

def earned_by_current_user
object.user_badges.exists?(user: context[:current_user])
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ class SpecialBadgeType < Types::BaseObject
field :display_data, Types::BadgeDisplayDataType, null: false
field :points, Integer, null: false
field :badge_type, String, null: false
field :current_user_badges, [Types::UserBadgeType], null: false
field :user_badges, [Types::UserBadgeType], null: false
field :earned_by_current_user, Boolean, null: false

def current_user_badges
Loaders::AssociationLoader.for(
Gamification::SpecialBadgeReadModel,
:user_badges
).load(object).then do |user_badges|
user_badges.where(user_id: context[:current_user].id)
end
def user_badges
object.user_badges.where(user: context[:current_user])
end

def earned_by_current_user
object.user_badges.exists?(user: context[:current_user])
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Gamification
class UserBadgeReadModel < ApplicationRecord
self.table_name = "user_badges"

belongs_to :user
belongs_to :user, class_name: "Authentication::UserReadModel", foreign_key: "user_id", primary_key: "user_id"
belongs_to :badgeable, polymorphic: true

validates :user_id, presence: true
Expand Down Expand Up @@ -38,3 +38,23 @@ def validate_uniqueness_for_normal_badges
end
end
end

# == Schema Information
#
# Table name: user_badges
#
# id :bigint not null, primary key
# badgeable_type :string not null
# earned_at :datetime not null
# created_at :datetime not null
# updated_at :datetime not null
# badgeable_id :string not null
# user_id :bigint not null
#
# Indexes
#
# index_user_badges_on_badgeable_type_and_badgeable_id (badgeable_type,badgeable_id)
# index_user_badges_on_earned_at (earned_at)
# index_user_badges_on_user_id (user_id)
# unique_normal_badges_index (user_id,badgeable_type,badgeable_id) UNIQUE WHERE ((badgeable_type)::text = 'Gamification::BadgeReadModel'::text)
#
15 changes: 14 additions & 1 deletion apps/govquests-api/rails_app/db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions apps/govquests-api/rails_app/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ type BackgroundGradient {

type Badge {
badgeable: BadgeableUnion
currentUserBadges: [UserBadge!]!
displayData: BadgeDisplayData!
earnedByCurrentUser: Boolean!
id: ID!
userBadges: [UserBadge!]!
}

type BadgeDisplayData {
Expand Down Expand Up @@ -655,10 +656,11 @@ type SignOutPayload {

type SpecialBadge {
badgeType: String!
currentUserBadges: [UserBadge!]!
displayData: BadgeDisplayData!
earnedByCurrentUser: Boolean!
id: ID!
points: Int!
userBadges: [UserBadge!]!
}

"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const SimpleBadgesSection: React.FC = () => {
<DialogTrigger>
<BadgeCard
badgeId={badge.id}
isCompleted={true}
isCompleted={badge.earnedByCurrentUser}
withTitle
header={`BADGE #${index + 1}`}
className="w-full"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const SpecialBadgesSection: React.FC = () => {
<DialogTrigger>
<BadgeCard
badgeId={badge.id}
isCompleted={true}
isCompleted={badge.earnedByCurrentUser}
withTitle
header={`SPECIAL BADGE #${index + 1}`}
className="w-full"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const BadgeQuery = graphql(`
query GetBadge($id: ID!) {
badge(id: $id) {
id
earnedByCurrentUser
displayData {
title
description
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const BadgesQuery = graphql(`
query GetBadges {
badges {
id
earnedByCurrentUser
}
}
`);
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const SpecialBadgeQuery = graphql(`
id
points
badgeType
earnedByCurrentUser
displayData {
title
description
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const SpecialBadgesQuery = graphql(`
query GetSpecialBadges {
specialBadges {
id
earnedByCurrentUser
}
}
`);
4 changes: 2 additions & 2 deletions apps/govquests-frontend/src/graphql-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type introspection_types = {
'ActionDisplayData': { kind: 'OBJECT'; name: 'ActionDisplayData'; fields: { 'description': { name: 'description'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'title': { name: 'title'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; }; };
'ActionExecution': { kind: 'OBJECT'; name: 'ActionExecution'; fields: { 'actionData': { name: 'actionData'; type: { kind: 'INTERFACE'; name: 'ActionDataInterface'; ofType: null; } }; 'actionId': { name: 'actionId'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'actionType': { name: 'actionType'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'completedAt': { name: 'completedAt'; type: { kind: 'SCALAR'; name: 'ISO8601DateTime'; ofType: null; } }; 'completionData': { name: 'completionData'; type: { kind: 'INTERFACE'; name: 'CompletionDataInterface'; ofType: null; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'nonce': { name: 'nonce'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'startData': { name: 'startData'; type: { kind: 'INTERFACE'; name: 'StartDataInterface'; ofType: null; } }; 'startedAt': { name: 'startedAt'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ISO8601DateTime'; ofType: null; }; } }; 'status': { name: 'status'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'userId': { name: 'userId'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; }; };
'BackgroundGradient': { kind: 'OBJECT'; name: 'BackgroundGradient'; fields: { 'fromColor': { name: 'fromColor'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'toColor': { name: 'toColor'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; }; };
'Badge': { kind: 'OBJECT'; name: 'Badge'; fields: { 'badgeable': { name: 'badgeable'; type: { kind: 'UNION'; name: 'BadgeableUnion'; ofType: null; } }; 'currentUserBadges': { name: 'currentUserBadges'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserBadge'; ofType: null; }; }; }; } }; 'displayData': { name: 'displayData'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'BadgeDisplayData'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; }; };
'Badge': { kind: 'OBJECT'; name: 'Badge'; fields: { 'badgeable': { name: 'badgeable'; type: { kind: 'UNION'; name: 'BadgeableUnion'; ofType: null; } }; 'displayData': { name: 'displayData'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'BadgeDisplayData'; ofType: null; }; } }; 'earnedByCurrentUser': { name: 'earnedByCurrentUser'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'userBadges': { name: 'userBadges'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserBadge'; ofType: null; }; }; }; } }; }; };
'BadgeDisplayData': { kind: 'OBJECT'; name: 'BadgeDisplayData'; fields: { 'description': { name: 'description'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'imageUrl': { name: 'imageUrl'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'title': { name: 'title'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; }; };
'BadgeableUnion': { kind: 'UNION'; name: 'BadgeableUnion'; fields: {}; possibleTypes: 'Quest' | 'Track'; };
'Boolean': unknown;
Expand Down Expand Up @@ -57,7 +57,7 @@ export type introspection_types = {
'SignInWithEthereumPayload': { kind: 'OBJECT'; name: 'SignInWithEthereumPayload'; fields: { 'clientMutationId': { name: 'clientMutationId'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'errors': { name: 'errors'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; }; } }; 'user': { name: 'user'; type: { kind: 'OBJECT'; name: 'User'; ofType: null; } }; }; };
'SignOutInput': { kind: 'INPUT_OBJECT'; name: 'SignOutInput'; isOneOf: false; inputFields: [{ name: 'clientMutationId'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }]; };
'SignOutPayload': { kind: 'OBJECT'; name: 'SignOutPayload'; fields: { 'clientMutationId': { name: 'clientMutationId'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'success': { name: 'success'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; } }; }; };
'SpecialBadge': { kind: 'OBJECT'; name: 'SpecialBadge'; fields: { 'badgeType': { name: 'badgeType'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'currentUserBadges': { name: 'currentUserBadges'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserBadge'; ofType: null; }; }; }; } }; 'displayData': { name: 'displayData'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'BadgeDisplayData'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'points': { name: 'points'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; } }; }; };
'SpecialBadge': { kind: 'OBJECT'; name: 'SpecialBadge'; fields: { 'badgeType': { name: 'badgeType'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'displayData': { name: 'displayData'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'BadgeDisplayData'; ofType: null; }; } }; 'earnedByCurrentUser': { name: 'earnedByCurrentUser'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'points': { name: 'points'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; } }; 'userBadges': { name: 'userBadges'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserBadge'; ofType: null; }; }; }; } }; }; };
'StartActionExecutionInput': { kind: 'INPUT_OBJECT'; name: 'StartActionExecutionInput'; isOneOf: false; inputFields: [{ name: 'actionId'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; }; defaultValue: null }, { name: 'actionType'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }, { name: 'clientMutationId'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'questId'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; }; defaultValue: null }, { name: 'sendEmailVerificationInput'; type: { kind: 'INPUT_OBJECT'; name: 'SendEmailVerificationInput'; ofType: null; }; defaultValue: null }]; };
'StartActionExecutionPayload': { kind: 'OBJECT'; name: 'StartActionExecutionPayload'; fields: { 'actionExecution': { name: 'actionExecution'; type: { kind: 'OBJECT'; name: 'ActionExecution'; ofType: null; } }; 'clientMutationId': { name: 'clientMutationId'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'errors': { name: 'errors'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; }; } }; }; };
'StartDataInterface': { kind: 'INTERFACE'; name: 'StartDataInterface'; fields: { 'actionType': { name: 'actionType'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; }; possibleTypes: 'DiscourseVerificationStartData' | 'EmptyActionStartData' | 'EnsStartData' | 'GitcoinScoreStartData' | 'SendEmailStartData'; };
Expand Down

0 comments on commit c287abe

Please sign in to comment.