Skip to content

Commit a58eab7

Browse files
bug: fixed leaderboard view
1 parent ff01827 commit a58eab7

File tree

6 files changed

+106
-61
lines changed

6 files changed

+106
-61
lines changed

actions/analytics/get-stripe-data.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,19 @@
33
import { Course, Purchase, PurchaseDetails } from '@prisma/client';
44

55
import { TEN_MINUTE_SEC } from '@/constants/common';
6+
import { DELAY_MS } from '@/constants/paginations';
67
import { fetchCachedData } from '@/lib/cache';
78
import { db } from '@/lib/db';
8-
import { sleep } from '@/lib/utils';
9+
import { getBatchedItems, sleep } from '@/lib/utils';
910
import { stripe } from '@/server/stripe';
1011

11-
const BATCH_SIZE = 10;
12-
const DELAY_MS = 500;
13-
1412
type PurchaseType = Purchase & { course: Course | null; details: PurchaseDetails | null };
1513

1614
type GetStripeData = {
1715
purchases: PurchaseType[];
1816
userId: string;
1917
};
2018

21-
const getBatchedItems = <T>(items: T[]) =>
22-
items.reduce(
23-
(batches, item, index) => {
24-
const batchIndex = Math.floor(index / BATCH_SIZE);
25-
26-
batches[batchIndex] ??= [];
27-
28-
if (item) {
29-
batches[batchIndex].push(item);
30-
}
31-
32-
return batches;
33-
},
34-
[] as (typeof items)[],
35-
);
36-
3719
export const getStripeData = async ({ purchases, userId }: GetStripeData) => {
3820
const accountId = await db.stripeConnectAccount.findUnique({ where: { userId } });
3921
const account = accountId?.stripeAccountId

actions/courses/get-leaders.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import groupBy from 'lodash.groupby';
44

55
import { CHAPTER_XP } from '@/constants/courses';
6+
import { DELAY_MS } from '@/constants/paginations';
67
import { db } from '@/lib/db';
78
import { isOwner as isOwnerFunc } from '@/lib/owner';
9+
import { getBatchedItems, sleep } from '@/lib/utils';
810

911
import { getUserSubscription } from '../stripe/get-user-subscription';
1012

@@ -42,17 +44,32 @@ export const getLeaders = async () => {
4244
})
4345
).filter((user) => user?.settings?.isPublicProfile);
4446

45-
const userSubscriptions = await Promise.all(
46-
users.map(async (user) => {
47-
const userSubscription = await getUserSubscription(user.id);
48-
const isOwner = isOwnerFunc(user.id);
49-
50-
return {
51-
hasSubscription: isOwner ?? Boolean(userSubscription),
52-
isOwner,
53-
userId: user.id,
54-
};
55-
}),
47+
const batchedUsers = getBatchedItems(users);
48+
49+
const userSubscriptions = await batchedUsers.reduce(
50+
async (previousUserSubscriptionsPromise: Promise<any[]>, batch: any[], batchIndex: number) => {
51+
const previousUserSubscriptions = await previousUserSubscriptionsPromise;
52+
53+
if (batchIndex > 0) {
54+
await sleep(DELAY_MS);
55+
}
56+
57+
const currentBatchUserSubscription = await Promise.all(
58+
batch.map(async (user) => {
59+
const userSubscription = await getUserSubscription(user.id);
60+
const isOwner = isOwnerFunc(user.id);
61+
62+
return {
63+
hasSubscription: isOwner || Boolean(userSubscription),
64+
isOwner,
65+
userId: user.id,
66+
};
67+
}),
68+
);
69+
70+
return previousUserSubscriptions.concat(currentBatchUserSubscription);
71+
},
72+
Promise.resolve([] as any[]),
5673
);
5774

5875
return Object.entries(groupedByUser)

actions/stripe/get-stripe-promo.ts

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import Stripe from 'stripe';
44

55
import { ONE_MINUTE_SEC } from '@/constants/common';
66
import { DEFAULT_LOCALE } from '@/constants/locale';
7-
import { PAGE_SIZES } from '@/constants/paginations';
7+
import { DELAY_MS, PAGE_SIZES } from '@/constants/paginations';
88
import { fetchCachedData } from '@/lib/cache';
99
import { db } from '@/lib/db';
1010
import { formatPrice, getConvertedPrice } from '@/lib/format';
11+
import { getBatchedItems, sleep } from '@/lib/utils';
1112
import { stripe } from '@/server/stripe';
1213

1314
type StripePromotionCodes = Stripe.Response<Stripe.ApiList<Stripe.PromotionCode>>['data'];
@@ -110,36 +111,65 @@ export const getStripePromo = async ({
110111

111112
const coupons = await stripe.coupons.list({ limit: 10 });
112113

113-
const stripePromos = await Promise.all(
114-
promos.map(async (code) => {
115-
const data = await fetchCachedData(
116-
`${code.id}-${code.stripePromoId}`,
117-
async () => {
118-
const res = await stripe.promotionCodes.retrieve(code.stripePromoId);
114+
const batchedStripePromos = getBatchedItems(promos);
115+
const batchedStripeCustomers = getBatchedItems(customers);
119116

120-
return res;
121-
},
122-
ONE_MINUTE_SEC,
117+
const stripePromos = await batchedStripePromos.reduce(
118+
async (previousStripePromosPromise: Promise<any[]>, batch: any[], batchIndex: number) => {
119+
const previousStripePromos = await previousStripePromosPromise;
120+
121+
if (batchIndex > 0) {
122+
await sleep(DELAY_MS);
123+
}
124+
125+
const currentBatchStripePromos = await Promise.all(
126+
batch.map(async (code) => {
127+
const data = await fetchCachedData(
128+
`${code.id}-${code.stripePromoId}`,
129+
async () => {
130+
const res = await stripe.promotionCodes.retrieve(code.stripePromoId);
131+
132+
return res;
133+
},
134+
ONE_MINUTE_SEC,
135+
);
136+
137+
return data;
138+
}),
123139
);
124140

125-
return data;
126-
}),
141+
return previousStripePromos.concat(currentBatchStripePromos);
142+
},
143+
Promise.resolve([] as any[]),
127144
);
128145

129-
const stripeCustomers = await Promise.all(
130-
customers.map(async (cs) => {
131-
const data = await fetchCachedData(
132-
`${cs.stripeCustomerId}`,
133-
async () => {
134-
const res = await stripe.customers.retrieve(cs.stripeCustomerId);
146+
const stripeCustomers = await batchedStripeCustomers.reduce(
147+
async (previousStripeCustomersPromise: Promise<any[]>, batch: any[], batchIndex: number) => {
148+
const previousStripeCustomers = await previousStripeCustomersPromise;
149+
150+
if (batchIndex > 0) {
151+
await sleep(DELAY_MS);
152+
}
153+
154+
const currentBatchStripeCustomers = await Promise.all(
155+
batch.map(async (cs) => {
156+
const data = await fetchCachedData(
157+
`${cs.stripeCustomerId}`,
158+
async () => {
159+
const res = await stripe.customers.retrieve(cs.stripeCustomerId);
160+
161+
return res;
162+
},
163+
ONE_MINUTE_SEC,
164+
);
135165

136-
return res;
137-
},
138-
ONE_MINUTE_SEC,
166+
return data;
167+
}),
139168
);
140169

141-
return data;
142-
}),
170+
return previousStripeCustomers.concat(currentBatchStripeCustomers);
171+
},
172+
Promise.resolve([] as any[]),
143173
);
144174

145175
return {

components/auth/user-profile-button.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,13 @@ export const UserProfileButton = ({ globalProgress }: UserProfileButtonProps) =>
4646
const handleSettings = () => router.push('/settings/general');
4747

4848
const isAdmin = user?.role === UserRole.ADMIN;
49-
const isStudent = user?.role === UserRole.STUDENT;
5049
const isTeacher = user?.role === UserRole.TEACHER;
5150

5251
return user ? (
5352
<DropdownMenu>
5453
<DropdownMenuTrigger asChild className="relative block hover:cursor-pointer">
5554
<Avatar className="w-[40px] h-[40px] border dark:border-muted-foreground">
56-
<AvatarImage src={user.image || ''} />
55+
<AvatarImage src={user.image ?? ''} />
5756
<AvatarFallback>{getFallbackName(user.name as string)}</AvatarFallback>
5857
</Avatar>
5958
</DropdownMenuTrigger>
@@ -66,11 +65,7 @@ export const UserProfileButton = ({ globalProgress }: UserProfileButtonProps) =>
6665
{user.hasSubscription && <TextBadge label={t('premium')} variant="lime" />}
6766
</div>
6867
</div>
69-
<p className="text-xs leading-none text-muted-foreground">
70-
{(isOwner(user.userId) || isAdmin) && t('admin')}
71-
{isTeacher && t('teacher')}
72-
{isStudent && t('student')}
73-
</p>
68+
<p className="text-xs leading-none text-muted-foreground">{t(user.role)}</p>
7469
<p className="text-xs leading-none text-muted-foreground">{user.email}</p>
7570
</div>
7671
</DropdownMenuLabel>

constants/paginations.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
export const PAGE_SIZES = [5, 10, 25, 50];
2+
3+
export const BATCH_SIZE = 10;
4+
export const DELAY_MS = 500;

lib/utils.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { type ClassValue, clsx } from 'clsx';
22
import { AES, enc } from 'crypto-js';
33
import { twMerge } from 'tailwind-merge';
44

5+
import { BATCH_SIZE } from '@/constants/paginations';
6+
57
export const cn = (...inputs: ClassValue[]) => {
68
return twMerge(clsx(inputs));
79
};
@@ -84,3 +86,19 @@ export const base64ToBlob = (base64: string, contentType: string = '') => {
8486
};
8587

8688
export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
89+
90+
export const getBatchedItems = <T>(items: T[]) =>
91+
items.reduce(
92+
(batches, item, index) => {
93+
const batchIndex = Math.floor(index / BATCH_SIZE);
94+
95+
batches[batchIndex] ??= [];
96+
97+
if (item) {
98+
batches[batchIndex].push(item);
99+
}
100+
101+
return batches;
102+
},
103+
[] as (typeof items)[],
104+
);

0 commit comments

Comments
 (0)