Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/shared/src/components/DataTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import { formatDataTileValue } from '../lib/numberFormat';

interface DataTileProps {
label: string;
value: number;
value: number | ReactNode;
info?: string;
icon?: ReactNode;
subtitle?: ReactNode;
valueClassName?: string;
className?: {
container?: string;
};
Expand All @@ -24,6 +25,7 @@ export const DataTile: React.FC<DataTileProps> = ({
info,
icon,
subtitle,
valueClassName,
className,
}) => {
return (
Expand All @@ -41,10 +43,14 @@ export const DataTile: React.FC<DataTileProps> = ({
</span>
</Tooltip>
</span>
<span className="flex flex-row items-center gap-1">
<span className="flex min-w-0 flex-row items-center gap-1">
{icon}
<Typography type={TypographyType.Title2} bold>
{formatDataTileValue(value)}
<Typography
type={TypographyType.Title2}
bold
className={classNames('min-w-0', valueClassName)}
>
{typeof value === 'number' ? formatDataTileValue(value) : value}
</Typography>
</span>
{subtitle}
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/src/components/quest/QuestButton.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ const questDashboard = {
xpInLevel: 250,
xpToNextLevel: 150,
},
currentStreak: 0,
longestStreak: 0,
daily: {
regular: [
{
Expand Down
5 changes: 5 additions & 0 deletions packages/shared/src/graphql/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,11 @@ export const TOP_READER_BADGE_FRAGMENT = gql`
issuedAt
image
total
user {
name
username
image
}
keyword {
value
flags {
Expand Down
47 changes: 47 additions & 0 deletions packages/shared/src/graphql/leaderboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,25 @@ export enum LeaderboardType {
MostReadingDays = 'mostReadingDays',
MostVerifiedUsers = 'mostVerifiedUsers',
MostAchievementPoints = 'mostAchievementPoints',
MostQuestsCompleted = 'mostQuestsCompleted',
HighestLevel = 'highestLevel',
}

export const MOST_QUESTS_COMPLETED_LIMIT = 10;

export type QuestCompletionLeader = {
questId: string;
questName: string;
questDescription: string;
count: number;
};

export type QuestCompletionStats = {
totalCount: number;
allTimeLeader: QuestCompletionLeader | null;
weeklyLeader: QuestCompletionLeader | null;
};

export const leaderboardTypeToTitle: Record<LeaderboardType, string> = {
[LeaderboardType.HighestReputation]: 'Highest reputation',
[LeaderboardType.LongestStreak]: 'Longest streak',
Expand All @@ -68,6 +84,7 @@ export const leaderboardTypeToTitle: Record<LeaderboardType, string> = {
[LeaderboardType.MostReadingDays]: 'Most reading days',
[LeaderboardType.MostVerifiedUsers]: 'Most verified employees',
[LeaderboardType.MostAchievementPoints]: 'Most achievement points',
[LeaderboardType.MostQuestsCompleted]: 'Most quests completed',
[LeaderboardType.HighestLevel]: 'Highest level',
};

Expand Down Expand Up @@ -137,6 +154,35 @@ export const MOST_ACHIEVEMENT_POINTS_QUERY = gql`
${LEADERBOARD_FRAGMENT}
`;

export const MOST_QUESTS_COMPLETED_QUERY = gql`
query MostQuestsCompleted($limit: Int = ${MOST_QUESTS_COMPLETED_LIMIT}) {
mostQuestsCompleted(limit: $limit) {
...LeaderboardFragment
}
}
${LEADERBOARD_FRAGMENT}
`;

export const QUEST_COMPLETION_STATS_QUERY = gql`
query QuestCompletionStats {
questCompletionStats {
totalCount
allTimeLeader {
questId
questName
questDescription
count
}
weeklyLeader {
questId
questName
questDescription
count
}
}
}
`;

export const HIGHEST_LEVEL_QUERY = gql`
query HighestLevel($limit: Int = 100) {
highestLevel(limit: $limit) {
Expand Down Expand Up @@ -172,6 +218,7 @@ export const leaderboardQueries: Record<LeaderboardType, string> = {
[LeaderboardType.MostReferrals]: MOST_REFERRALS_QUERY,
[LeaderboardType.MostReadingDays]: MOST_READING_DAYS_QUERY,
[LeaderboardType.MostAchievementPoints]: MOST_ACHIEVEMENT_POINTS_QUERY,
[LeaderboardType.MostQuestsCompleted]: MOST_QUESTS_COMPLETED_QUERY,
[LeaderboardType.HighestLevel]: HIGHEST_LEVEL_QUERY,
[LeaderboardType.MostVerifiedUsers]: MOST_VERIFIED_USERS_QUERY,
};
6 changes: 5 additions & 1 deletion packages/shared/src/graphql/quests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export interface QuestLevel {

export interface QuestDashboard {
level: QuestLevel;
currentStreak: number;
longestStreak: number;
daily: QuestBucket;
weekly: QuestBucket;
}
Expand All @@ -68,7 +70,7 @@ export interface QuestDashboardData {
}

export interface ClaimQuestRewardData {
claimQuestReward: QuestDashboard;
claimQuestReward: Pick<QuestDashboard, 'level' | 'daily' | 'weekly'>;
}

export interface QuestUpdate {
Expand Down Expand Up @@ -107,6 +109,8 @@ export const QUEST_DASHBOARD_QUERY = gql`
xpInLevel
xpToNextLevel
}
currentStreak
longestStreak
daily {
regular {
userQuestId
Expand Down
21 changes: 21 additions & 0 deletions packages/shared/src/graphql/users.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { TOP_READER_BADGE, TOP_READER_BADGE_BY_ID } from './users';

describe('top reader badge queries', () => {
it('includes the badge owner in the list query', () => {
expect(TOP_READER_BADGE).toContain(
'topReaderBadge(limit: $limit, userId: $userId)',
);
expect(TOP_READER_BADGE).toContain('user {');
expect(TOP_READER_BADGE).toContain('name');
expect(TOP_READER_BADGE).toContain('username');
expect(TOP_READER_BADGE).toContain('image');
});

it('includes the badge owner in the by-id query', () => {
expect(TOP_READER_BADGE_BY_ID).toContain('topReaderBadgeById(id: $id)');
expect(TOP_READER_BADGE_BY_ID).toContain('user {');
expect(TOP_READER_BADGE_BY_ID).toContain('name');
expect(TOP_READER_BADGE_BY_ID).toContain('username');
expect(TOP_READER_BADGE_BY_ID).toContain('image');
});
});
5 changes: 0 additions & 5 deletions packages/shared/src/graphql/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -794,11 +794,6 @@ export const TOP_READER_BADGE_BY_ID = gql`
query TopReaderBadgeById($id: ID!) {
topReaderBadgeById(id: $id) {
...TopReader
user {
name
username
image
}
}
}

Expand Down
36 changes: 33 additions & 3 deletions packages/shared/src/hooks/useClaimQuestReward.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useAuthContext } from '../contexts/AuthContext';
import { useLogContext } from '../contexts/LogContext';
import type { ClaimQuestRewardData, QuestType } from '../graphql/quests';
import type {
ClaimQuestRewardData,
QuestDashboard,
QuestType,
} from '../graphql/quests';
import { CLAIM_QUEST_REWARD_MUTATION } from '../graphql/quests';
import { LogEvent, TargetType } from '../lib/log';
import { generateQueryKey, RequestKey } from '../lib/query';
Expand Down Expand Up @@ -31,7 +35,7 @@ export const useClaimQuestReward = () => {

return result.claimQuestReward;
},
onSuccess: async (questDashboard, { userQuestId, questId, questType }) => {
onSuccess: async (claimResult, { userQuestId, questId, questType }) => {
logEvent({
event_name: LogEvent.ClaimQuest,
target_id: questId,
Expand All @@ -43,7 +47,33 @@ export const useClaimQuestReward = () => {
}),
});

queryClient.setQueryData(questDashboardKey, questDashboard);
let didUpdateQuestDashboard = false;

queryClient.setQueryData<QuestDashboard | undefined>(
questDashboardKey,
(currentDashboard) => {
if (!currentDashboard) {
return currentDashboard;
}

didUpdateQuestDashboard = true;

return {
...currentDashboard,
level: claimResult.level,
daily: claimResult.daily,
weekly: claimResult.weekly,
};
},
);

if (!didUpdateQuestDashboard) {
await queryClient.invalidateQueries({
queryKey: questDashboardKey,
exact: true,
});
}

await refetchBoot?.();
},
});
Expand Down
Loading
Loading