···130130 flushesPerDay = parseFloat(((totalCount || 0) / activeDaysCount).toFixed(1));
131131 }
132132133133+ // Calculate Monthly Active Flushers (MAFs)
134134+ // This is the number of unique DIDs that have posted at least once in the past 30 days
135135+ const thirtyDaysAgo = new Date();
136136+ thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
137137+138138+ // Filter records to get only those from the last 30 days
139139+ const recentRecords = dailyData?.filter(entry =>
140140+ new Date(entry.created_at) >= thirtyDaysAgo
141141+ );
142142+143143+ // Get unique DIDs from recent records
144144+ const recentUniqueDids = new Set<string>();
145145+ recentRecords?.forEach(entry => {
146146+ if (entry.did) {
147147+ recentUniqueDids.add(entry.did);
148148+ }
149149+ });
150150+151151+ const monthlyActiveFlushers = recentUniqueDids.size;
152152+ console.log(`Monthly Active Flushers (last 30 days): ${monthlyActiveFlushers}`);
153153+154154+ // Calculate Daily Active Flushers (DAFs)
155155+ // This is the average number of unique users who post per day over the last 30 days
156156+ const dailyActiveUserCounts = new Map<string, Set<string>>();
157157+158158+ // Group users by day
159159+ recentRecords?.forEach(entry => {
160160+ const date = new Date(entry.created_at);
161161+ const dateKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
162162+163163+ if (!dailyActiveUserCounts.has(dateKey)) {
164164+ dailyActiveUserCounts.set(dateKey, new Set<string>());
165165+ }
166166+167167+ if (entry.did) {
168168+ dailyActiveUserCounts.get(dateKey)!.add(entry.did);
169169+ }
170170+ });
171171+172172+ // Calculate average daily active users
173173+ let dailyActiveFlushers = 0;
174174+ if (dailyActiveUserCounts.size > 0) {
175175+ const totalDailyActiveUsers = Array.from(dailyActiveUserCounts.values()).reduce(
176176+ (total, users) => total + users.size, 0
177177+ );
178178+ dailyActiveFlushers = parseFloat((totalDailyActiveUsers / dailyActiveUserCounts.size).toFixed(1));
179179+ }
180180+ console.log(`Daily Active Flushers (average over last 30 days): ${dailyActiveFlushers}`);
181181+133182 // 3. Get top flushers (leaderboard) - excluding test accounts
134183 const { data: leaderboardData, error: leaderboardError } = await supabase
135184 .from('flushing_records')
···194243 chartData: chartData.slice(-30), // Last 30 days
195244 leaderboard,
196245 plumberFlushCount,
197197- totalFlushers
246246+ totalFlushers,
247247+ monthlyActiveFlushers,
248248+ dailyActiveFlushers
198249 });
199250 } else {
200251 // If no Supabase credentials, return mock data
···204255 chartData: generateMockChartData(),
205256 leaderboard: generateMockLeaderboard(),
206257 plumberFlushCount: 15,
207207- totalFlushers: 28
258258+ totalFlushers: 28,
259259+ monthlyActiveFlushers: 18,
260260+ dailyActiveFlushers: 5.2
208261 });
209262 }
210263 } catch (error: any) {
+11-1
app/src/app/stats/page.tsx
···1313 leaderboard: { did: string; count: number; handle?: string }[];
1414 plumberFlushCount: number;
1515 totalFlushers: number;
1616+ monthlyActiveFlushers: number;
1717+ dailyActiveFlushers: number;
1618}
17191820export default function StatsPage() {
···185187 <div className={styles.statValue}>{statsData.totalFlushers}</div>
186188 <div className={styles.statLabel}>Total flushers</div>
187189 </div>
190190+ <div className={styles.statCard}>
191191+ <div className={styles.statValue}>{statsData.monthlyActiveFlushers}</div>
192192+ <div className={styles.statLabel}>Monthly active flushers</div>
193193+ </div>
194194+ <div className={styles.statCard}>
195195+ <div className={styles.statValue}>{statsData.dailyActiveFlushers}</div>
196196+ <div className={styles.statLabel}>Daily active flushers (avg)</div>
197197+ </div>
188198 </div>
189199 </section>
190200···262272 className={styles.shareButton}
263273 onClick={() => {
264274 // Generate share text
265265- const statsText = `There have been ${statsData.totalCount} flushes by ${statsData.totalFlushers} unique users on @flushes.app! That's averaging ${statsData.flushesPerDay} flushes per active day. Check out the stats and leaderboard: https://flushes.app/stats`;
275275+ const statsText = `There have been ${statsData.totalCount} flushes by ${statsData.totalFlushers} unique users on @flushes.app! We have ${statsData.monthlyActiveFlushers} monthly active flushers and ${statsData.dailyActiveFlushers} daily active flushers on average. Check out the stats: https://flushes.app/stats`;
266276 window.open(`https://bsky.app/intent/compose?text=${encodeURIComponent(statsText)}`, '_blank');
267277 }}
268278 >