From 1881032ed201b22863e3cc44233e8547b31f339e Mon Sep 17 00:00:00 2001 From: "fredy.siswanto" Date: Sat, 8 Mar 2025 20:25:41 +0700 Subject: [PATCH] feat: implement social share buttons --- app/components/ui/social-share.tsx | 103 ++++++++++++++++------------- app/pages/news-detail/index.tsx | 19 ++++-- package.json | 1 + pnpm-lock.yaml | 25 +++++++ 4 files changed, 95 insertions(+), 53 deletions(-) diff --git a/app/components/ui/social-share.tsx b/app/components/ui/social-share.tsx index dc14aee..f59d1e2 100644 --- a/app/components/ui/social-share.tsx +++ b/app/components/ui/social-share.tsx @@ -1,59 +1,70 @@ -import type { FC } from 'react' -import { Link } from 'react-router' -import { twMerge } from 'tailwind-merge' +import { LinkIcon } from '@heroicons/react/20/solid' +import { useState } from 'react' +import { + FacebookShareButton, + LinkedinShareButton, + TwitterShareButton, + InstapaperShareButton, +} from 'react-share' import { FacebookIcon } from '~/components/icons/facebook' import { InstagramIcon } from '~/components/icons/instagram' -import { LinkIcon } from '~/components/icons/link-icon' import { LinkedinIcon } from '~/components/icons/linkedin' import { XIcon } from '~/components/icons/x' -type SocialMediaProperties = { - className?: string - slug?: string +type SocialShareButtonsProperties = { + url: string + title: string } -const dataSocialMedia = [ - { - type: 'link', - url: 'post-id/', - icon: LinkIcon, - }, - { - type: 'facebook', - url: 'https://facebook.com/', - icon: FacebookIcon, - }, - { - type: 'linkedin', - url: 'https://linkedin.com/', - icon: LinkedinIcon, - }, - { - type: 'x', - url: 'https://x.com/', - icon: XIcon, - }, - { - type: 'instagram', - url: 'https://instagram.com/', - icon: InstagramIcon, - }, -] +export const SocialShareButtons = ({ + url, + title, +}: SocialShareButtonsProperties) => { + const [showPopup, setShowPopup] = useState(false) -export const IconsSocial: FC = ({ className }) => { + const handleCopyLink = () => { + navigator.clipboard.writeText(url) + setShowPopup(true) + setTimeout(() => setShowPopup(false), 2000) + } return ( -
- {dataSocialMedia.map(({ url, icon: Icon }, index) => ( - - - - ))} +
+ {showPopup && ( +
+ Link berhasil disalin! +
+ )} + + + + + + + + + + + + + + + +
) } diff --git a/app/pages/news-detail/index.tsx b/app/pages/news-detail/index.tsx index 23a1c68..d1a4c19 100644 --- a/app/pages/news-detail/index.tsx +++ b/app/pages/news-detail/index.tsx @@ -4,7 +4,7 @@ import { useRouteLoaderData } from 'react-router' import type { TTagResponse } from '~/apis/common/get-tags' import { Card } from '~/components/ui/card' import { CarouselSection } from '~/components/ui/carousel-section' -import { IconsSocial } from '~/components/ui/social-share' +import { SocialShareButtons } from '~/components/ui/social-share' import { BERITA } from '~/data/contents' import type { loader } from '~/routes/_news.detail.$slug' import { formatDate } from '~/utils/formatter' @@ -13,10 +13,10 @@ export const NewsDetailPage = () => { const loaderData = useRouteLoaderData( 'routes/_news.detail.$slug', ) - + const currentUrl = globalThis.location // eslint-disable-next-line @typescript-eslint/no-explicit-any const { newsDetailData }: any = loaderData - const { title, content, featured_image, slug, author, live_at, tags } = + const { title, content, featured_image, author, live_at, tags } = newsDetailData return ( @@ -40,7 +40,11 @@ export const NewsDetailPage = () => {

{formatDate(live_at)} . 5 min read

- + {/* */} + {/* end next planing create component for this section */}
@@ -59,9 +63,10 @@ export const NewsDetailPage = () => {

Share this post

-
diff --git a/package.json b/package.json index 707b41b..e09abeb 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "react-dom": "^19.0.0", "react-hook-form": "^7.54.2", "react-router": "^7.1.3", + "react-share": "^5.2.2", "remix-hook-form": "^6.1.3", "tailwind-merge": "^3.0.1", "xior": "^0.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c41056b..b000427 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,6 +95,9 @@ importers: react-router: specifier: ^7.1.3 version: 7.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-share: + specifier: ^5.2.2 + version: 5.2.2(react@19.0.0) remix-hook-form: specifier: ^6.1.3 version: 6.1.3(react-dom@19.0.0(react@19.0.0))(react-hook-form@7.54.2(react@19.0.0))(react-router@7.1.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) @@ -3130,6 +3133,9 @@ packages: jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonp@0.2.1: + resolution: {integrity: sha512-pfog5gdDxPdV4eP7Kg87M8/bHgshlZ5pybl+yKxAnCZ5O7lCIn7Ixydj03wOlnDQesky2BPyA91SQ+5Y/mNwzw==} + jsonparse@1.3.1: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} @@ -3945,6 +3951,11 @@ packages: react-dom: optional: true + react-share@5.2.2: + resolution: {integrity: sha512-z0nbOX6X6vHHWAvXduNkYeJUKTKNpKM5Xpmc5a2BxjJhUWl+sE7AsSEMmYEUj2DuDjZr5m7KFIGF0sQPKcUN6w==} + peerDependencies: + react: ^17 || ^18 || ^19 + react-simple-animate@3.5.3: resolution: {integrity: sha512-Ob+SmB5J1tXDEZyOe2Hf950K4M8VaWBBmQ3cS2BUnTORqHjhK0iKG8fB+bo47ZL15t8d3g/Y0roiqH05UBjG7A==} peerDependencies: @@ -7894,6 +7905,12 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonp@0.2.1: + dependencies: + debug: 2.6.9 + transitivePeerDependencies: + - supports-color + jsonparse@1.3.1: {} jsx-ast-utils@3.3.5: @@ -8683,6 +8700,14 @@ snapshots: optionalDependencies: react-dom: 19.0.0(react@19.0.0) + react-share@5.2.2(react@19.0.0): + dependencies: + classnames: 2.5.1 + jsonp: 0.2.1 + react: 19.0.0 + transitivePeerDependencies: + - supports-color + react-simple-animate@3.5.3(react-dom@19.0.0(react@19.0.0)): dependencies: react-dom: 19.0.0(react@19.0.0)