Skip to content

Commit

Permalink
Merge pull request #47 from unmonk/v0.2
Browse files Browse the repository at this point in the history
minor tweaks to months end actions
  • Loading branch information
unmonk authored Dec 1, 2024
2 parents 1e9cb2d + b95d042 commit 2a9b21f
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 101 deletions.
170 changes: 90 additions & 80 deletions convex/campaigns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { api, internal } from "./_generated/api";
import { v } from "convex/values";

export const createMonthlyCampaign = internalAction({
args: {},
args: {
dryRun: v.optional(v.boolean()),
},
returns: v.string(),
handler: async (ctx) => {
handler: async (ctx, { dryRun }) => {
//get the current active global campaign
const activeGlobalCampaign = await ctx.runQuery(
api.campaigns.getActiveGlobalCampaign,
Expand Down Expand Up @@ -42,34 +44,35 @@ export const createMonthlyCampaign = internalAction({

if (!chains || chains.length === 0) {
console.log("No chains found for active global campaign");
//throw new Error("No chains found for active global campaign");
}

//get chain with highest chain number
const highestChain = chains.reduce((prev, current) => {
if (prev.chain > current.chain) return prev;
if (prev.chain < current.chain) return current;
// If chains are equal, check wins
if (prev.wins > current.wins) return prev;
if (prev.wins < current.wins) return current;
// If wins are equal, check pushes
if (prev.pushes > current.pushes) return prev;
if (prev.pushes < current.pushes) return current;
// If everything is equal, keep the first one
return prev;
// First compare chains
if (prev.chain !== current.chain) {
return prev.chain > current.chain ? prev : current;
}
// If chains are equal, compare wins
if (prev.wins !== current.wins) {
return prev.wins > current.wins ? prev : current;
}
// If wins are equal, compare pushes (higher pushes wins)
return prev.pushes >= current.pushes ? prev : current;
});

//get chain with highest win number
const highestWin = chains.reduce((prev, current) => {
if (prev.wins > current.wins) return prev;
if (prev.wins < current.wins) return current;
// If wins are equal, check pushes
if (prev.pushes > current.pushes) return prev;
if (prev.pushes < current.pushes) return current;
// If everything is equal, keep the first one
return prev;
// First compare wins
if (prev.wins !== current.wins) {
return prev.wins > current.wins ? prev : current;
}
// If wins are equal, compare pushes (higher pushes wins)
return prev.pushes >= current.pushes ? prev : current;
});

console.log("Highest Chain", highestChain);
console.log("Highest Win", highestWin);

if (!highestChain) {
console.log("No Chain Winner");
//throw new Error("No Chain Winner");
Expand All @@ -84,74 +87,81 @@ export const createMonthlyCampaign = internalAction({
activeGlobalCampaign.chainWinnerId = highestChain.userId;
activeGlobalCampaign.winnerId = highestWin.userId;

//save the completed global campaign
await ctx.runMutation(internal.campaigns.saveCompletedCampaign, {
active: activeGlobalCampaign.active,
chainWinnerId: activeGlobalCampaign.chainWinnerId,
winnerId: activeGlobalCampaign.winnerId,
campaignId: activeGlobalCampaign._id,
});

//deactivate all chains
await ctx.runMutation(internal.chains.deactivateAllChains, {
campaignId: activeGlobalCampaign._id,
});

//todo notifications
if (!dryRun) {
//save the completed global campaign
await ctx.runMutation(internal.campaigns.saveCompletedCampaign, {
active: activeGlobalCampaign.active,
chainWinnerId: activeGlobalCampaign.chainWinnerId,
winnerId: activeGlobalCampaign.winnerId,
campaignId: activeGlobalCampaign._id,
});

//award highest chain winner
if (monthlyChainWinAchievement) {
await ctx.scheduler.runAfter(0, api.achievements.awardAchievement, {
userId: highestChain.userId,
achievementId: monthlyChainWinAchievement._id,
//deactivate all chains
await ctx.runMutation(internal.chains.deactivateAllChains, {
campaignId: activeGlobalCampaign._id,
});

//todo notifications

//award highest chain winner
if (monthlyChainWinAchievement) {
await ctx.scheduler.runAfter(0, api.achievements.awardAchievement, {
userId: highestChain.userId,
achievementId: monthlyChainWinAchievement._id,
});
}

//award highest win winner
if (monthlyWinAchievement) {
await ctx.scheduler.runAfter(0, api.achievements.awardAchievement, {
userId: highestWin.userId,
achievementId: monthlyWinAchievement._id,
});
}
}

//award highest win winner
if (monthlyWinAchievement) {
await ctx.scheduler.runAfter(0, api.achievements.awardAchievement, {
userId: highestWin.userId,
achievementId: monthlyWinAchievement._id,
if (!dryRun) {
//create a new global campaign
const date = new Date();
const month = date.toLocaleString("en-US", { month: "long" });
const year = date.getFullYear();
const campaignName = `${month} ${year} Monthly Global Campaign`;
const campaignDescription = `The monthly global campaign for ${month} ${year}, all users participate in this campaign.`;
//start date is first day of the month at 10am utc
const startDate = new Date(
date.getFullYear(),
date.getMonth(),
1,
10,
0,
0
);
//end date is last day of the month at 09:59:30 utc
const endDate = new Date(
date.getFullYear(),
date.getMonth() + 1,
0,
9,
59,
30
);

await ctx.runMutation(internal.campaigns.createGlobalCampaign, {
name: campaignName,
description: campaignDescription,
active: true,
featured: true,
type: "GLOBAL",
startDate: startDate.getTime(),
endDate: endDate.getTime(),
ownedBy: "SYSTEM",
});
return `Created ${campaignName}`;
}
return `Dry Run Completed`;
}

//create a new global campaign
const date = new Date();
const month = date.toLocaleString("en-US", { month: "long" });
const year = date.getFullYear();
const campaignName = `${month} ${year} Monthly Global Campaign`;
const campaignDescription = `The monthly global campaign for ${month} ${year}, all users participate in this campaign.`;
//start date is first day of the month at 10am utc
const startDate = new Date(
date.getFullYear(),
date.getMonth(),
1,
10,
0,
0
);
//end date is last day of the month at 09:59:30 utc
const endDate = new Date(
date.getFullYear(),
date.getMonth() + 1,
0,
9,
59,
30
);

await ctx.runMutation(internal.campaigns.createGlobalCampaign, {
name: campaignName,
description: campaignDescription,
active: true,
featured: true,
type: "GLOBAL",
startDate: startDate.getTime(),
endDate: endDate.getTime(),
ownedBy: "SYSTEM",
});
return `Created ${campaignName}`;
return "Campaign processing completed";
},
});

Expand Down
6 changes: 4 additions & 2 deletions convex/crons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ crons.daily(
crons.monthly(
"Monthly Campaign Finalization, Achievement Awards, and New Campaign Creation",
{ day: 1, hourUTC: 10, minuteUTC: 0 }, // 1st of the month at 10:00 UTC, Midnight HST
internal.campaigns.createMonthlyCampaign
internal.campaigns.createMonthlyCampaign,
{ dryRun: false }
);

crons.monthly(
"Record monthly statistics for all players",
{ day: 1, hourUTC: 9, minuteUTC: 45 }, // last day of the month at 11:45 PM HST
internal.users.monthlyStatsRecord
internal.users.monthlyStatsRecord,
{ dryRun: false }
);

export default crons;
15 changes: 13 additions & 2 deletions convex/leaderboards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,19 @@ export const getChainLeaderboard = query({
.withIndex("by_active", (q) => q.eq("active", true))
.collect();

//sort chains by best chain
chains.sort((a, b) => b.chain - a.chain);
//sort chains by best chain, then wins, then pushes
chains.sort((a, b) => {
// First compare chains
if (a.chain !== b.chain) {
return b.chain - a.chain;
}
// If chains are equal, compare wins
if (a.wins !== b.wins) {
return b.wins - a.wins;
}
// If wins are equal, compare pushes
return b.pushes - a.pushes;
});

return Promise.all(
(chains as any[]).map(async (chain, index) => {
Expand Down
53 changes: 36 additions & 17 deletions convex/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,19 +347,28 @@ export const updateUserMonthlyStats = internalMutation({
_id: v.id("users"),
monthlyStats: v.any(),
}),
dryRun: v.optional(v.boolean()),
},
handler: async (ctx, { user }) => {
await ctx.db.patch(user._id, {
monthlyStats: {
...user.monthlyStats,
},
});
handler: async (ctx, { user, dryRun }) => {
if (dryRun) {
console.log("UPDATING MONTHLY STATS");
console.log(user.monthlyStats);
}
if (!dryRun) {
await ctx.db.patch(user._id, {
monthlyStats: {
...user.monthlyStats,
},
});
}
},
});

export const monthlyStatsRecord = internalAction({
args: {},
handler: async (ctx) => {
args: {
dryRun: v.optional(v.boolean()),
},
handler: async (ctx, { dryRun }) => {
const users = await ctx.runQuery(api.users.getAllUsers);
for (const user of users) {
if (!user.monthlyStats) {
Expand All @@ -376,24 +385,34 @@ export const monthlyStatsRecord = internalAction({
currentStats.totalGames =
user.stats.wins + user.stats.losses + user.stats.pushes;
if (currentStats.totalGames > 0) {
currentStats.winRate = user.stats.wins / currentStats.totalGames;
currentStats.winRate = Number(
(user.stats.wins / currentStats.totalGames).toFixed(2)
);
}
if (currentStats.totalGames === 0) {
currentStats.winRate = 0;
}
currentStats.coins = user.coins;
currentStats.statsByLeague = user.stats.statsByLeague;

await ctx.runMutation(internal.users.updateUserMonthlyStats, {
user: {
_id: user._id,
monthlyStats: {
...user.monthlyStats,
[currentMonth]: currentStats,
if (dryRun) {
console.log("CURRENT STATS", currentMonth, user.name);
console.log(currentStats);
}

if (!dryRun) {
await ctx.runMutation(internal.users.updateUserMonthlyStats, {
user: {
_id: user._id,
monthlyStats: {
...user.monthlyStats,
[currentMonth]: currentStats,
},
},
},
});
});
}
}
return "Monthly stats processing completed";
},
});

Expand Down

0 comments on commit 2a9b21f

Please sign in to comment.