···5050 .map(([date, count]): {date: string, count: number} => ({ date, count }))
5151 .sort((a, b) => a.date.localeCompare(b.date));
52525353- // Calculate flushes per day
5353+ // Calculate flushes per day based on actual active days
5454 let flushesPerDay = 0;
5555 if (chartData.length > 0 && totalCount !== null) {
5656- // Calculate days between first and last flush
5757- const firstDate = new Date(chartData[0].date);
5858- const lastDate = new Date(chartData[chartData.length - 1].date);
5959- const daysDiff = Math.max(1, Math.ceil((lastDate.getTime() - firstDate.getTime()) / (1000 * 60 * 60 * 24)));
6060- flushesPerDay = parseFloat(((totalCount || 0) / daysDiff).toFixed(1));
5656+ // Use the number of days with at least one flush (which is the length of chartData)
5757+ // This gives us the actual active days count
5858+ const activeDaysCount = chartData.length;
5959+ flushesPerDay = parseFloat(((totalCount || 0) / activeDaysCount).toFixed(1));
6160 }
62616362 // 3. Get top flushers (leaderboard)
···5555 setSelectedEmoji(emoji);
5656 };
57575858- // Check rate limit - 2 posts per 30 minutes
5858+ // Check rate limit - 2 posts per 30 minutes, except for the plumber account
5959 const checkRateLimit = (): boolean => {
6060+ // Exempt the plumber account from rate limiting
6161+ if (did === 'did:plc:fouf3svmcxzn6bpiw3lgwz22') {
6262+ console.log('Plumber account detected - bypassing rate limits');
6363+ return true; // Always return true (under limit) for the plumber account
6464+ }
6565+6066 const now = Date.now();
6167 const thirtyMinutesAgo = now - 30 * 60 * 1000; // 30 minutes in milliseconds
6268···86928793 // Check for banned words
8894 if (text && containsBannedWords(text)) {
8989- setStatusError('Your status contains inappropriate language. Please revise it.');
9595+ setStatusError('Uh oh, looks like you have a potty mouth. Try flushing again, but go a bit easier on the language please... this is a semi-family-friendly restroom');
9096 return;
9197 }
92989393- // Check rate limit - 2 posts per 30 minutes
9999+ // Check rate limit - 2 posts per 30 minutes (except for the plumber account)
94100 if (!checkRateLimit()) {
9595- setStatusError("Trying to make more than 2 flushes in 30 minutes?? Might be time to get the plunger. 🪠");
101101+ setStatusError("Trying to make more than 2 flushes in 30 minutes?? Might be time to get the plunger. 🪠 Regular users are limited to 2 flushes per 30 minutes.");
96102 return;
97103 }
98104···238244 // Function to load older entries
239245 const loadOlderEntries = async () => {
240246 try {
247247+ // Save current scroll position
248248+ const scrollPosition = window.scrollY;
249249+241250 setLoading(true);
242251 setError(null);
243252···267276 if (data.entries && data.entries.length > 0) {
268277 // Append the new entries to our existing list
269278 setEntries([...entries, ...data.entries]);
279279+280280+ // Wait for DOM to update with new entries
281281+ setTimeout(() => {
282282+ // Restore scroll position after state update and render
283283+ window.scrollTo({
284284+ top: scrollPosition,
285285+ behavior: 'instant' // Use instant to avoid additional animation
286286+ });
287287+ }, 0);
270288 }
271289 } catch (err: any) {
272290 console.error('Error fetching older entries:', err);
···466484467485 <button
468486 className={styles.loadMoreButton}
469469- onClick={loadOlderEntries}
487487+ onClick={(e) => {
488488+ e.preventDefault(); // Prevent default action
489489+ loadOlderEntries();
490490+ }}
470491 disabled={loading}
471492 >
472493 {loading ? 'Loading...' : 'Load older flushes'}
+13-15
app/src/app/profile/[handle]/page.tsx
···60606161 // Calculate statistics and chart data
6262 if (userEntries.length > 0) {
6363- // Calculate flushes per day
6464- const sortedEntries = [...userEntries].sort((a: FlushingEntry, b: FlushingEntry) =>
6565- new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
6666- );
6363+ // Calculate actual active days count (days with at least one flush)
6464+ const dateSet = new Set<string>();
6565+ userEntries.forEach((entry: FlushingEntry) => {
6666+ const date = new Date(entry.created_at);
6767+ const dateKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
6868+ dateSet.add(dateKey);
6969+ });
67706868- if (sortedEntries.length > 1) {
6969- const firstDate = new Date(sortedEntries[0].created_at);
7070- const lastDate = new Date(sortedEntries[sortedEntries.length - 1].created_at);
7171- const daysDiff = Math.max(1, Math.ceil((lastDate.getTime() - firstDate.getTime()) / (1000 * 60 * 60 * 24)));
7272- const perDay = parseFloat((sortedEntries.length / daysDiff).toFixed(1));
7373- setFlushesPerDay(perDay);
7474- } else {
7575- setFlushesPerDay(1); // Just one flush on a single day
7676- }
7171+ // Calculate true average: total flushes divided by number of active days
7272+ const activeDaysCount = Math.max(1, dateSet.size);
7373+ const perDay = parseFloat((userEntries.length / activeDaysCount).toFixed(1));
7474+ setFlushesPerDay(perDay);
77757876 // Generate chart data (group by day)
7977 const chartDataMap = new Map<string, number>();
···148146 <h3 className={styles.statsHeader}>Flushing Statistics</h3>
149147 <p className={styles.statDetails}>
150148 {totalCount} total {totalCount === 1 ? 'flush' : 'flushes'}
151151- {flushesPerDay > 0 && `, ${flushesPerDay} ${flushesPerDay === 1 ? 'flush' : 'flushes'} per day`}
149149+ {flushesPerDay > 0 && `, averaging ${flushesPerDay} ${flushesPerDay === 1 ? 'flush' : 'flushes'} per active day`}
152150 </p>
153151154152 {chartData.length > 0 ? (
···183181 className={styles.shareStatsButton}
184182 onClick={() => {
185183 // Open a new window to compose a post on Bluesky
186186- const statsText = `I've made ${totalCount} decentralized ${totalCount === 1 ? 'flush' : 'flushes'}${flushesPerDay > 0 ? ` (or ${flushesPerDay} per day)` : ''} on @flushing.im. Flush with me here: https://flushing.im/profile/${handle}`;
184184+ const statsText = `I've made ${totalCount} decentralized ${totalCount === 1 ? 'flush' : 'flushes'}${flushesPerDay > 0 ? ` (averaging ${flushesPerDay} per active day)` : ''} on @flushing.im. Flush with me here: https://flushing.im/profile/${handle}`;
187185 window.open(`https://bsky.app/intent/compose?text=${encodeURIComponent(statsText)}`, '_blank');
188186 }}
189187 >
···157157 </div>
158158 <div className={styles.statCard}>
159159 <div className={styles.statValue}>{statsData.flushesPerDay}</div>
160160- <div className={styles.statLabel}>Flushes Per Day</div>
160160+ <div className={styles.statLabel}>Flushes Per Active Day</div>
161161 </div>
162162 </div>
163163 </section>
···236236 className={styles.shareButton}
237237 onClick={() => {
238238 // Generate share text
239239- const statsText = `There have been ${statsData.totalCount} flushes on @flushing.im! That's ${statsData.flushesPerDay} flushes per day. Check out the stats and leaderboard: https://flushing.im/stats`;
239239+ const statsText = `There have been ${statsData.totalCount} flushes on @flushing.im! That's averaging ${statsData.flushesPerDay} flushes per active day. Check out the stats and leaderboard: https://flushing.im/stats`;
240240 window.open(`https://bsky.app/intent/compose?text=${encodeURIComponent(statsText)}`, '_blank');
241241 }}
242242 >