|
|
@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'; |
|
|
|
import { isLoggedIn } from '../../lib/jwt'; |
|
|
|
import { isLoggedIn } from '../../lib/jwt'; |
|
|
|
import { httpGet } from '../../lib/http'; |
|
|
|
import { httpGet } from '../../lib/http'; |
|
|
|
import { useToast } from '../../hooks/use-toast'; |
|
|
|
import { useToast } from '../../hooks/use-toast'; |
|
|
|
import { Flame, X, Zap, ZapOff } from 'lucide-react'; |
|
|
|
import { Flame, UserPlus, X, Zap, ZapOff } from 'lucide-react'; |
|
|
|
import { useOutsideClick } from '../../hooks/use-outside-click'; |
|
|
|
import { useOutsideClick } from '../../hooks/use-outside-click'; |
|
|
|
import { StreakDay } from './StreakDay'; |
|
|
|
import { StreakDay } from './StreakDay'; |
|
|
|
import { |
|
|
|
import { |
|
|
@ -11,15 +11,9 @@ import { |
|
|
|
} from '../../stores/page.ts'; |
|
|
|
} from '../../stores/page.ts'; |
|
|
|
import { useStore } from '@nanostores/react'; |
|
|
|
import { useStore } from '@nanostores/react'; |
|
|
|
import { cn } from '../../lib/classname.ts'; |
|
|
|
import { cn } from '../../lib/classname.ts'; |
|
|
|
import { $accountStreak } from '../../stores/streak.ts'; |
|
|
|
import { $accountStreak, type StreakResponse } from '../../stores/streak.ts'; |
|
|
|
|
|
|
|
import { useCopyText } from '../../hooks/use-copy-text.ts'; |
|
|
|
type StreakResponse = { |
|
|
|
import { useAuth } from '../../hooks/use-auth.ts'; |
|
|
|
count: number; |
|
|
|
|
|
|
|
longestCount: number; |
|
|
|
|
|
|
|
previousCount?: number | null; |
|
|
|
|
|
|
|
firstVisitAt: Date; |
|
|
|
|
|
|
|
lastVisitAt: Date; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type AccountStreakProps = {}; |
|
|
|
type AccountStreakProps = {}; |
|
|
|
|
|
|
|
|
|
|
@ -27,6 +21,8 @@ export function AccountStreak(props: AccountStreakProps) { |
|
|
|
const toast = useToast(); |
|
|
|
const toast = useToast(); |
|
|
|
const dropdownRef = useRef(null); |
|
|
|
const dropdownRef = useRef(null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const user = useAuth(); |
|
|
|
|
|
|
|
const { copyText } = useCopyText(); |
|
|
|
const [isLoading, setIsLoading] = useState(true); |
|
|
|
const [isLoading, setIsLoading] = useState(true); |
|
|
|
const accountStreak = useStore($accountStreak); |
|
|
|
const accountStreak = useStore($accountStreak); |
|
|
|
const [showDropdown, setShowDropdown] = useState(false); |
|
|
|
const [showDropdown, setShowDropdown] = useState(false); |
|
|
@ -77,6 +73,16 @@ export function AccountStreak(props: AccountStreakProps) { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const shareReferralLink = () => { |
|
|
|
|
|
|
|
const referralLink = new URL( |
|
|
|
|
|
|
|
`/signup?rc=${user?.id}`, |
|
|
|
|
|
|
|
import.meta.env.DEV ? 'http://localhost:3000' : 'https://roadmap.sh', |
|
|
|
|
|
|
|
).toString(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
copyText(referralLink); |
|
|
|
|
|
|
|
toast.success('Referral link copied to clipboard'); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let { count: currentCount = 0 } = accountStreak || {}; |
|
|
|
let { count: currentCount = 0 } = accountStreak || {}; |
|
|
|
const previousCount = |
|
|
|
const previousCount = |
|
|
|
accountStreak?.previousCount || accountStreak?.count || 0; |
|
|
|
accountStreak?.previousCount || accountStreak?.count || 0; |
|
|
@ -184,11 +190,52 @@ export function AccountStreak(props: AccountStreakProps) { |
|
|
|
<p className="-mt-[0px] mb-[1.5px] text-center text-xs tracking-wide text-slate-500"> |
|
|
|
<p className="-mt-[0px] mb-[1.5px] text-center text-xs tracking-wide text-slate-500"> |
|
|
|
Visit every day to keep your streak going! |
|
|
|
Visit every day to keep your streak going! |
|
|
|
</p> |
|
|
|
</p> |
|
|
|
<p className='text-xs mt-1.5 text-center'> |
|
|
|
<p className="mt-1.5 text-center text-xs"> |
|
|
|
<a href="/leaderboard" className="text-purple-400 hover:underline underline-offset-2"> |
|
|
|
<a |
|
|
|
|
|
|
|
href="/leaderboard" |
|
|
|
|
|
|
|
className="text-purple-400 underline-offset-2 hover:underline" |
|
|
|
|
|
|
|
> |
|
|
|
See how you compare to others |
|
|
|
See how you compare to others |
|
|
|
</a> |
|
|
|
</a> |
|
|
|
</p> |
|
|
|
</p> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{accountStreak?.refByUserCount ? ( |
|
|
|
|
|
|
|
<div className="mt-5"> |
|
|
|
|
|
|
|
<div className="flex items-center gap-2 text-sm text-slate-500"> |
|
|
|
|
|
|
|
<UserPlus className="size-4" /> |
|
|
|
|
|
|
|
<p> |
|
|
|
|
|
|
|
<span className="text-slate-200"> |
|
|
|
|
|
|
|
{accountStreak?.refByUserCount || 0} |
|
|
|
|
|
|
|
</span>{' '} |
|
|
|
|
|
|
|
user(s) joined through{' '} |
|
|
|
|
|
|
|
<button |
|
|
|
|
|
|
|
className="text-slate-200 no-underline underline-offset-2 hover:underline" |
|
|
|
|
|
|
|
onClick={shareReferralLink} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
your referral |
|
|
|
|
|
|
|
</button> |
|
|
|
|
|
|
|
. |
|
|
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
) : null} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{!accountStreak?.refByUserCount && ( |
|
|
|
|
|
|
|
<div className="mt-5"> |
|
|
|
|
|
|
|
<div className="flex items-center gap-2 text-sm text-slate-500"> |
|
|
|
|
|
|
|
<UserPlus className="size-4" /> |
|
|
|
|
|
|
|
<p> |
|
|
|
|
|
|
|
<button |
|
|
|
|
|
|
|
className="text-slate-200 no-underline underline-offset-2 hover:underline" |
|
|
|
|
|
|
|
onClick={shareReferralLink} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
Share your referral |
|
|
|
|
|
|
|
</button>{' '} |
|
|
|
|
|
|
|
link with your friends. |
|
|
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
)} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
)} |
|
|
|
)} |
|
|
|