This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

Refactor Profile Page Chart Data to Group by Month

- Updated the chart data generation logic to group user entries by month instead of day, allowing for a broader view of flushing statistics.
- Enhanced the chart data structure to include all months in the range from the first entry to the current month.
- Adjusted date formatting in the chart legend to reflect monthly data.
- Made CSS adjustments to improve the layout and styling of the wrapped cards section.

+50 -45
+41 -27
src/app/profile/[handle]/page.tsx
··· 341 341 const perDay = parseFloat((userEntries.length / activeDaysCount).toFixed(1)); 342 342 setFlushesPerDay(perDay); 343 343 344 - // Generate chart data (group by day) 345 - const chartDataMap = new Map<string, number>(); 344 + // Generate chart data (group by month) 345 + const monthDataMap = new Map<string, number>(); 346 346 347 - // Group entries by day 347 + // Group entries by month 348 348 userEntries.forEach((entry: FlushingEntry) => { 349 349 const date = new Date(entry.created_at); 350 - const dateKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`; 350 + const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`; 351 351 352 - if (chartDataMap.has(dateKey)) { 353 - chartDataMap.set(dateKey, chartDataMap.get(dateKey)! + 1); 354 - } else { 355 - chartDataMap.set(dateKey, 1); 356 - } 352 + monthDataMap.set(monthKey, (monthDataMap.get(monthKey) || 0) + 1); 357 353 }); 358 354 359 - // Convert map to array and sort by date 360 - const chartDataArray = Array.from(chartDataMap.entries()) 361 - .map(([date, count]): {date: string, count: number} => ({ date, count })) 362 - .sort((a, b) => a.date.localeCompare(b.date)); 363 - 364 - // Limit to last 30 days for chart readability 365 - const limitedData = chartDataArray.slice(-30); 366 - setChartData(limitedData); 355 + // Find the range of months from first flush to current month 356 + if (userEntries.length > 0) { 357 + // Find the oldest and newest entries 358 + const sortedByDate = [...userEntries].sort((a, b) => 359 + new Date(a.created_at).getTime() - new Date(b.created_at).getTime() 360 + ); 361 + const firstEntry = sortedByDate[0]; 362 + const firstDate = new Date(firstEntry.created_at); 363 + const lastDate = new Date(); // Current date 364 + 365 + // Generate all months in the range 366 + const allMonths: {date: string, count: number}[] = []; 367 + const currentMonth = new Date(firstDate.getFullYear(), firstDate.getMonth(), 1); 368 + const endMonth = new Date(lastDate.getFullYear(), lastDate.getMonth(), 1); 369 + 370 + while (currentMonth <= endMonth) { 371 + const monthKey = `${currentMonth.getFullYear()}-${String(currentMonth.getMonth() + 1).padStart(2, '0')}`; 372 + allMonths.push({ 373 + date: monthKey, 374 + count: monthDataMap.get(monthKey) || 0 375 + }); 376 + 377 + // Move to next month 378 + currentMonth.setMonth(currentMonth.getMonth() + 1); 379 + } 380 + 381 + setChartData(allMonths); 382 + } else { 383 + setChartData([]); 384 + } 367 385 } else { 368 386 setFlushesPerDay(0); 369 387 setChartData([]); ··· 431 449 432 450 <div className={styles.wrappedCards}> 433 451 <div className={styles.wrappedCard}> 434 - <div className={styles.wrappedCardIcon}>🚽</div> 435 452 <div className={styles.wrappedCardValue}>{wrappedStats.totalFlushes.toLocaleString()}</div> 436 453 <div className={styles.wrappedCardLabel}>Total Flushes</div> 437 454 </div> 438 455 439 456 <div className={styles.wrappedCard}> 440 - <div className={styles.wrappedCardIcon}>📅</div> 441 457 <div className={styles.wrappedCardValue}>{wrappedStats.daysActive}</div> 442 458 <div className={styles.wrappedCardLabel}>Days Active</div> 443 459 </div> 444 460 445 461 {wrappedStats.mostFrequentHour !== null && ( 446 462 <div className={styles.wrappedCard}> 447 - <div className={styles.wrappedCardIcon}>⏰</div> 448 463 <div className={styles.wrappedCardValue}> 449 464 {wrappedStats.mostFrequentHour === 0 ? '12' : wrappedStats.mostFrequentHour > 12 ? wrappedStats.mostFrequentHour - 12 : wrappedStats.mostFrequentHour} 450 465 {wrappedStats.mostFrequentHour >= 12 ? 'PM' : 'AM'} ··· 454 469 )} 455 470 456 471 <div className={styles.wrappedCard}> 457 - <div className={styles.wrappedCardIcon}>{wrappedStats.topEmoji}</div> 458 472 <div className={styles.wrappedCardValue}>{wrappedStats.topEmoji}</div> 459 473 <div className={styles.wrappedCardLabel}>Top Emoji</div> 460 474 </div> 461 475 462 476 {wrappedStats.mostFlushesInDay > 0 && ( 463 477 <div className={styles.wrappedCard}> 464 - <div className={styles.wrappedCardIcon}>🔥</div> 465 478 <div className={styles.wrappedCardValue}>{wrappedStats.mostFlushesInDay}</div> 466 479 <div className={styles.wrappedCardLabel}>Most in One Day</div> 467 480 </div> ··· 469 482 470 483 {wrappedStats.longestStreak > 0 && ( 471 484 <div className={styles.wrappedCard}> 472 - <div className={styles.wrappedCardIcon}>⚡</div> 473 485 <div className={styles.wrappedCardValue}>{wrappedStats.longestStreak}</div> 474 486 <div className={styles.wrappedCardLabel}>Day Streak</div> 475 487 </div> ··· 492 504 {chartData.map((dataPoint, index) => { 493 505 // Calculate height percentage (max of 100%) 494 506 const maxCount = Math.max(...chartData.map(d => d.count)); 495 - const heightPercent = Math.max(10, Math.min(100, (dataPoint.count / maxCount) * 100)); 507 + const heightPercent = maxCount > 0 508 + ? Math.max(10, Math.min(100, (dataPoint.count / maxCount) * 100)) 509 + : 0; 496 510 497 511 return ( 498 512 <div 499 513 key={index} 500 514 className={styles.chartBar} 501 515 style={{ height: `${heightPercent}%` }} 502 - title={`${dataPoint.date}: ${dataPoint.count} flushes`} 516 + title={`${new Date(dataPoint.date + '-01').toLocaleDateString(undefined, { month: 'long', year: 'numeric' })}: ${dataPoint.count} flushes`} 503 517 /> 504 518 ); 505 519 })} ··· 507 521 508 522 <div className={styles.chartLegend}> 509 523 <span className={styles.chartLegendItem}> 510 - {chartData.length > 0 ? new Date(chartData[0].date).toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) : ''} 524 + {chartData.length > 0 ? new Date(chartData[0].date + '-01').toLocaleDateString(undefined, { month: 'short', year: 'numeric' }) : ''} 511 525 </span> 512 526 <span className={styles.chartLegendItem}> 513 - {chartData.length > 0 ? new Date(chartData[chartData.length - 1].date).toLocaleDateString(undefined, { month: 'short', day: 'numeric' }) : ''} 527 + {chartData.length > 0 ? new Date(chartData[chartData.length - 1].date + '-01').toLocaleDateString(undefined, { month: 'short', year: 'numeric' }) : ''} 514 528 </span> 515 529 </div> 516 530
+9 -18
src/app/profile/[handle]/profile.module.css
··· 93 93 /* Flushes Wrapped Section */ 94 94 .wrappedSection { 95 95 background-color: var(--card-background); 96 - padding: 2.5rem 1.5rem; 97 - margin-bottom: 2rem; 98 - box-shadow: 0 4px 12px var(--shadow-color); 96 + border-radius: 8px; 97 + padding: 1.5rem; 98 + margin-bottom: 1.5rem; 99 + box-shadow: 0 2px 5px var(--shadow-color); 99 100 border: 1px solid var(--tile-border); 100 101 } 101 102 ··· 126 127 127 128 .wrappedCard { 128 129 background-color: var(--input-background); 130 + border-radius: 8px; 129 131 padding: 1.5rem 1rem; 130 132 text-align: center; 131 133 display: flex; ··· 133 135 align-items: center; 134 136 justify-content: center; 135 137 min-height: 160px; 136 - box-shadow: 0 2px 8px var(--shadow-color); 138 + box-shadow: 0 2px 5px var(--shadow-color); 137 139 border: 1px solid var(--tile-border); 138 140 transition: transform 0.2s, box-shadow 0.2s; 139 141 } ··· 143 145 box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25); 144 146 } 145 147 146 - .wrappedCardIcon { 147 - font-size: 2.5rem; 148 - margin-bottom: 0.75rem; 149 - line-height: 1; 150 - } 151 - 152 148 .wrappedCardValue { 153 149 font-size: 2.5rem; 154 150 font-weight: 700; ··· 168 164 169 165 @media (max-width: 600px) { 170 166 .wrappedSection { 171 - padding: 2rem 1rem; 167 + padding: 1.5rem; 172 168 } 173 169 174 170 .wrappedTitle { ··· 181 177 182 178 .wrappedCards { 183 179 grid-template-columns: repeat(2, 1fr); 184 - gap: 1rem; 180 + gap: 0.75rem; 185 181 } 186 182 187 183 .wrappedCard { 188 - padding: 1.25rem 0.75rem; 184 + padding: 1rem 0.5rem; 189 185 min-height: 140px; 190 - } 191 - 192 - .wrappedCardIcon { 193 - font-size: 2rem; 194 - margin-bottom: 0.5rem; 195 186 } 196 187 197 188 .wrappedCardValue {