Add activity page

pull/3985/head
Kamran Ahmed 1 year ago
parent 476557db80
commit 44949709d1
  1. 2
      src/components/Activity/ActivityCounters.tsx
  2. 8
      src/components/Activity/ActivityPage.tsx
  3. 6
      src/components/Activity/EmptyActivity.tsx
  4. 50
      src/components/Activity/ResourceProgress.tsx
  5. 4
      src/components/Navigation/Navigation.astro
  6. 30
      src/lib/date.ts

@ -47,7 +47,7 @@ export function ActivityCounters(props: ActivityCountersType) {
/>
<ActivityCounter
text={'Learning Streak'}
text={'Visit Streak'}
count={`${streak?.count || 0}d`}
/>
</div>

@ -20,6 +20,7 @@ type ActivityResponse = {
done: number;
total: number;
skipped: number;
updatedAt: string;
}[];
bestPractices: {
title: string;
@ -28,10 +29,13 @@ type ActivityResponse = {
done: number;
skipped: number;
total: number;
updatedAt: string;
}[];
};
streak: {
count: number;
firstVisitAt: Date | null;
lastVisitAt: Date | null;
};
activity: {
type: 'done' | 'learning' | 'pending' | 'skipped';
@ -52,7 +56,7 @@ export function ActivityPage() {
async function loadActivity() {
const { error, response } = await httpGet<ActivityResponse>(
`${import.meta.env.PUBLIC_API_URL}/v1-get-user-activity`
`${import.meta.env.PUBLIC_API_URL}/v1-get-user-stats`
);
if (!response || error) {
@ -105,6 +109,7 @@ export function ActivityPage() {
skippedCount={roadmap.skipped || 0}
resourceId={roadmap.id}
resourceType={'roadmap'}
updatedAt={roadmap.updatedAt}
title={roadmap.title}
onCleared={() => {
pageLoadingMessage.set('Updating activity');
@ -124,6 +129,7 @@ export function ActivityPage() {
skippedCount={bestPractice.skipped || 0}
resourceType={'best-practice'}
title={bestPractice.title}
updatedAt={bestPractice.updatedAt}
onCleared={() => {
pageLoadingMessage.set('Updating activity');
loadActivity().finally(() => {

@ -7,10 +7,10 @@ export function EmptyActivity() {
<img
alt="no roadmaps"
src={CheckIcon}
class="mb-2 h-[120px] w-[120px] opacity-10"
class="mb-2 w-[60px] h-[60px] sm:h-[120px] sm:w-[120px] opacity-10"
/>
<h2 class="text-xl font-bold">No Progress</h2>
<p className="my-2 max-w-[400px] text-gray-500">
<h2 class="text-lg sm:text-xl font-bold">No Progress</h2>
<p className="my-1 sm:my-2 max-w-[400px] text-gray-500 text-sm sm:text-base">
Progress will appear here as you start tracking your{' '}
<a href="/roadmaps" class="mt-4 text-blue-500 hover:underline">
Roadmaps

@ -1,10 +1,12 @@
import { useEffect, useState } from 'preact/hooks';
import { useState } from 'preact/hooks';
import { httpPost } from '../../lib/http';
import { getRelativeTimeString } from '../../lib/date';
type ResourceProgressType = {
resourceType: 'roadmap' | 'best-practice';
resourceId: string;
title: string;
updatedAt: string;
totalCount: number;
doneCount: number;
learningCount: number;
@ -17,6 +19,7 @@ export function ResourceProgress(props: ResourceProgressType) {
const [isConfirming, setIsConfirming] = useState(false);
const {
updatedAt,
resourceType,
resourceId,
title,
@ -71,16 +74,30 @@ export function ResourceProgress(props: ResourceProgressType) {
width: `${progressPercentage}%`,
}}
></span>
<span className="relative flex-1 cursor-pointer">{title}</span>
<span className="cursor-pointer text-sm text-gray-400">
5 hours ago
<span className="relative flex-1 cursor-pointer truncate">
{title}
</span>
<span className="ml-1 cursor-pointer text-sm text-gray-400">
{getRelativeTimeString(updatedAt)}
</span>
</a>
<p className="items-start sm:space-between flex flex-row rounded-b-md border border-t-0 px-2 py-2 text-xs text-gray-500">
<span className="flex-1 gap-1 flex">
<p className="sm:space-between flex flex-row items-start rounded-b-md border border-t-0 px-2 py-2 text-xs text-gray-500">
<span className="hidden flex-1 gap-1 sm:flex">
{doneCount > 0 && (
<>
<span>{doneCount} done</span> &bull;
{ learningCount > 0 && <><span>{learningCount} in progress</span> &bull;</> }
{ skippedCount > 0 && <><span>{skippedCount} skipped</span> &bull;</> }
</>
)}
{learningCount > 0 && (
<>
<span>{learningCount} in progress</span> &bull;
</>
)}
{skippedCount > 0 && (
<>
<span>{skippedCount} skipped</span> &bull;
</>
)}
<span>{totalCount} total</span>
</span>
{!isConfirming && (
@ -101,10 +118,19 @@ export function ResourceProgress(props: ResourceProgressType) {
{isConfirming && (
<span>
<span className='hidden sm:inline'>Are you sure?{' '}</span>
<span className='inline sm:hidden'>Sure?{' '}</span>
<button onClick={clearProgress} className="ml-1 mr-1 underline text-red-500 hover:text-red-800">Yes</button>{' '}
<button onClick={() => setIsConfirming(false)} className="underline text-red-500 hover:text-red-800">No</button>
Are you sure?{' '}
<button
onClick={clearProgress}
className="ml-1 mr-1 text-red-500 underline hover:text-red-800"
>
Yes
</button>{' '}
<button
onClick={() => setIsConfirming(false)}
className="text-red-500 underline hover:text-red-800"
>
No
</button>
</span>
)}
</p>

@ -26,8 +26,8 @@ import AccountDropdown from './AccountDropdown.astro';
<a href='/videos' class='text-gray-400 hover:text-white'>Videos</a>
</li>
<li>
<kbd data-command-menu class="hidden md:flex items-center text-gray-400 border border-gray-800 rounded-md px-2.5 py-1 text-sm hover:bg-gray-800 hover:cursor-pointer">
<!-- <Icon icon='search' class='h-3 w-3 mr-2' /> -->
<kbd data-command-menu class="hidden sm:flex items-center text-gray-400 border border-gray-800 rounded-md px-2.5 py-1 text-sm hover:bg-gray-800 hover:cursor-pointer">
<Icon icon='search' class='h-3 w-3 mr-2' />
<kbd class='font-sans mr-1'>⌘</kbd><kbd class='font-sans'>K</kbd>
</kbd>
</li>

@ -0,0 +1,30 @@
export function getRelativeTimeString(date: string): string {
if (!Intl?.RelativeTimeFormat) {
return date;
}
const rtf = new Intl.RelativeTimeFormat('en', {
numeric: 'auto',
style: 'narrow',
});
const currentDate = new Date();
const targetDate = new Date(date);
const diffInMilliseconds = currentDate.getTime() - targetDate.getTime();
const diffInMinutes = Math.round(diffInMilliseconds / (1000 * 60));
const diffInHours = Math.round(diffInMilliseconds / (1000 * 60 * 60));
const diffInDays = Math.round(diffInMilliseconds / (1000 * 60 * 60 * 24));
let relativeTime;
if (diffInMinutes < 60) {
relativeTime = rtf.format(-diffInMinutes, 'minute');
} else if (diffInHours < 24) {
relativeTime = rtf.format(-diffInHours, 'hour');
} else {
relativeTime = rtf.format(-diffInDays, 'day');
}
return relativeTime;
}
Loading…
Cancel
Save