Skip to content

Commit

Permalink
[#455] add hook useTimer, use hook in ShareButton, change prop name c…
Browse files Browse the repository at this point in the history
…ontent => tooltipContent
  • Loading branch information
Stonek79 authored and Themezv committed Oct 26, 2023
1 parent 0b77a90 commit 3a22239
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 31 deletions.
4 changes: 2 additions & 2 deletions apps/blog/src/app/[locale]/posts/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { generateFullUrl } from '@/utils/generateFullUrl'
import { memeberToPostAuthor } from '@/utils/memeberToPostAuthor'
import { formatDate } from '@/utils/formatDate'
import type { Language } from '@/i18n/i18n.settings'
import { ShareButton } from 'src/components/ShareButton'
import { ShareButton } from '@/components/ShareButton'
import { useTranslation } from '@/i18n'

interface BlogProps {
Expand Down Expand Up @@ -95,7 +95,7 @@ export default async function Post({ params }: BlogProps) {
<div className="flex justify-between items-center mb-4">
<p className="text-gray-600 text-sm">{formatDate(post.publishedAt, params.locale)}</p>
<ShareButton
content={t('copied')}
tooltipContent={t('copied')}
shareData={{ title: post.title, text: post.summary, url: generateFullUrl(`/${params.locale}/posts/${post.slug}`) }}
/>
</div>
Expand Down
45 changes: 16 additions & 29 deletions apps/blog/src/components/ShareButton/ShareButton.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,32 @@
'use client'

import React, { useCallback, useEffect, useRef, useState } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import * as Popover from '@radix-ui/react-popover'
import { useTimer } from '@/utils/hooks/useTimer'

const popoverTimer = 1000

export const ShareButton = ({ shareData, content }: { shareData: ShareData; content: string }) => {
export const ShareButton = ({ shareData, tooltipContent }: { shareData: ShareData; tooltipContent: string }) => {
const [open, setOpen] = useState(false)
const timerIdRef = useRef<NodeJS.Timeout | null>(null)

const handleTimerClear = useCallback(() => {
if (timerIdRef.current) {
clearTimeout(timerIdRef.current)
timerIdRef.current = null
}
}, [])

const handleStartTimer = useCallback(() => {
timerIdRef.current = setTimeout(() => {
setOpen(false)
handleTimerClear()
}, popoverTimer)
}, [handleTimerClear])
const setPopoverClosed = useCallback(() => setOpen(false), [setOpen])
const { startTimer, stopTimer } = useTimer(setPopoverClosed, popoverTimer)

const handlePopoverClick = useCallback(() => {
const handlePopoverOpen = useCallback(() => {
if (open) {
setOpen(false)
handleTimerClear()
stopTimer()
} else {
setOpen(true)
handleTimerClear()
handleStartTimer()
startTimer()
}
}, [handleStartTimer, handleTimerClear, open])
}, [startTimer, stopTimer, open])

useEffect(
() => () => {
handleTimerClear()
stopTimer()
},
[handleTimerClear],
[stopTimer],
)

/**
Expand All @@ -53,23 +41,23 @@ export const ShareButton = ({ shareData, content }: { shareData: ShareData; cont
try {
if (!navigator.share) {
await navigator.clipboard.writeText(shareData.url || shareData.text || shareData.title || '')
handlePopoverClick()
handlePopoverOpen()
} else {
await navigator.share(shareData)
}
} catch (error: unknown) {
handleTimerClear()
stopTimer()

if (error instanceof Error && error.name === 'AbortError') {
return
}

console.error(error)
}
}, [handlePopoverClick, handleTimerClear, shareData])
}, [handlePopoverOpen, stopTimer, shareData])

return (
<Popover.Root open={open} defaultOpen onOpenChange={handleClick}>
<Popover.Root open={open} onOpenChange={handleClick}>
<Popover.Trigger className="flex" asChild>
<svg
className="items-center justify-end opacity-30 hover:text-memebattleYellow hover:opacity-100"
Expand All @@ -90,9 +78,8 @@ export const ShareButton = ({ shareData, content }: { shareData: ShareData; cont
side="top"
align="end"
sideOffset={5}
hideWhenDetached
>
{content}
{tooltipContent}
<Popover.Arrow className="fill-gray-200" width={10} height={10} />
</Popover.Content>
</Popover.Portal>
Expand Down
28 changes: 28 additions & 0 deletions apps/blog/src/utils/hooks/useTimer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useEffect, useRef, useCallback } from 'react'

interface TimerFunctions {
startTimer: () => void
stopTimer: () => void
}

export function useTimer(callback: () => void, delay = 2000): TimerFunctions {
const timerRef = useRef<NodeJS.Timeout | null>(null)

const startTimer = useCallback(() => {
if (timerRef.current) {
clearTimeout(timerRef.current)
}
timerRef.current = setTimeout(callback, delay)
}, [callback, delay])

const stopTimer = useCallback(() => {
if (timerRef.current) {
clearTimeout(timerRef.current)
timerRef.current = null
}
}, [])

useEffect(() => stopTimer, [stopTimer])

return { startTimer, stopTimer }
}

0 comments on commit 3a22239

Please sign in to comment.