Implement Social Share options (#4569)

* Implement social share options

* Minor fix
pull/4576/head
Arik Chakma 1 year ago committed by GitHub
parent 6f9fe361ae
commit 16662ed699
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      src/components/CreateTeam/RoadmapSelector.tsx
  2. 1
      src/components/CustomRoadmap/PersonalRoadmapList.tsx
  3. 1
      src/components/CustomRoadmap/ResourceProgressStats.tsx
  4. 5
      src/components/CustomRoadmap/RoadmapHeader.tsx
  5. 66
      src/components/ShareOptions/CopyRoadmapLink.tsx
  6. 11
      src/components/ShareOptions/ShareOptionsModal.tsx
  7. 115
      src/components/ShareOptions/ShareSuccess.tsx
  8. 1
      src/components/TeamRoadmapsList/TeamRoadmaps.tsx

@ -15,6 +15,7 @@ import { useToast } from '../../hooks/use-toast';
export type TeamResourceConfig = { export type TeamResourceConfig = {
isCustomResource: boolean; isCustomResource: boolean;
title: string; title: string;
description?: string;
visibility?: AllowedRoadmapVisibility; visibility?: AllowedRoadmapVisibility;
resourceId: string; resourceId: string;
resourceType: string; resourceType: string;

@ -60,6 +60,7 @@ export function PersonalRoadmapList(props: PersonalRoadmapListType) {
const shareSettingsModal = selectedRoadmap && ( const shareSettingsModal = selectedRoadmap && (
<ShareOptionsModal <ShareOptionsModal
description={selectedRoadmap.description}
visibility={selectedRoadmap.visibility} visibility={selectedRoadmap.visibility}
sharedFriendIds={selectedRoadmap.sharedFriendIds} sharedFriendIds={selectedRoadmap.sharedFriendIds}
sharedTeamMemberIds={selectedRoadmap.sharedTeamMemberIds} sharedTeamMemberIds={selectedRoadmap.sharedTeamMemberIds}

@ -24,6 +24,7 @@ export function ResourceProgressStats(props: ResourceProgressStatsProps) {
<> <>
{isSharing && $canManageCurrentRoadmap && $currentRoadmap && ( {isSharing && $canManageCurrentRoadmap && $currentRoadmap && (
<ShareOptionsModal <ShareOptionsModal
description={$currentRoadmap?.description}
visibility={$currentRoadmap?.visibility} visibility={$currentRoadmap?.visibility}
teamId={$currentRoadmap?.teamId} teamId={$currentRoadmap?.teamId}
roadmapId={$currentRoadmap?._id!} roadmapId={$currentRoadmap?._id!}

@ -121,6 +121,7 @@ export function RoadmapHeader(props: RoadmapHeaderProps) {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{isSharing && $currentRoadmap && ( {isSharing && $currentRoadmap && (
<ShareOptionsModal <ShareOptionsModal
description={$currentRoadmap?.description}
visibility={$currentRoadmap?.visibility} visibility={$currentRoadmap?.visibility}
teamId={$currentRoadmap?.teamId} teamId={$currentRoadmap?.teamId}
roadmapId={$currentRoadmap?._id!} roadmapId={$currentRoadmap?._id!}
@ -143,7 +144,7 @@ export function RoadmapHeader(props: RoadmapHeaderProps) {
$currentRoadmap?._id $currentRoadmap?._id
}`} }`}
target="_blank" target="_blank"
className="inline-flex items-center justify-center rounded-md bg-white py-1.5 pl-2 pr-2 text-xs font-medium text-black hover:bg-gray-300 hover:border-gray-300 sm:px-3 sm:text-sm border border-gray-300" className="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white py-1.5 pl-2 pr-2 text-xs font-medium text-black hover:border-gray-300 hover:bg-gray-300 sm:px-3 sm:text-sm"
> >
<Shapes className="mr-1.5 h-4 w-4 stroke-[2.5]" /> <Shapes className="mr-1.5 h-4 w-4 stroke-[2.5]" />
<span className="hidden sm:inline-block">Edit Roadmap</span> <span className="hidden sm:inline-block">Edit Roadmap</span>
@ -151,7 +152,7 @@ export function RoadmapHeader(props: RoadmapHeaderProps) {
</a> </a>
<button <button
onClick={() => setIsSharing(true)} onClick={() => setIsSharing(true)}
className="inline-flex items-center justify-center rounded-md bg-white py-1.5 pl-2 pr-2 text-xs font-medium text-black hover:bg-gray-300 hover:border-gray-300 sm:px-3 sm:text-sm border border-gray-300" className="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white py-1.5 pl-2 pr-2 text-xs font-medium text-black hover:border-gray-300 hover:bg-gray-300 sm:px-3 sm:text-sm"
> >
<Lock className="mr-1.5 h-4 w-4 stroke-[2.5]" /> <Lock className="mr-1.5 h-4 w-4 stroke-[2.5]" />
Sharing Sharing

@ -1,66 +0,0 @@
import { CheckCircle, Copy } from 'lucide-react';
import { useCopyText } from '../../hooks/use-copy-text';
import { cn } from '../../lib/classname';
type CopyRoadmapLinkProps = {
roadmapId: string;
onClose: () => void;
};
export function CopyRoadmapLink(props: CopyRoadmapLinkProps) {
const { roadmapId, onClose } = props;
const baseUrl = import.meta.env.DEV
? 'http://localhost:3000'
: 'https://roadmap.sh';
const shareLink = `${baseUrl}/r?id=${roadmapId}`;
const { copyText, isCopied } = useCopyText();
return (
<div className="flex grow flex-col justify-center">
<div className="mt-5 flex grow flex-col items-center justify-center gap-1.5">
<CheckCircle className="h-14 w-14 text-green-500" />
<h3 className="text-xl font-medium">Sharing Settings Updated</h3>
</div>
<input
type="text"
className="mt-6 w-full rounded-md border bg-gray-50 p-2 px-2.5 text-gray-700 focus:outline-none"
value={shareLink}
readOnly
onClick={(e) => {
e.currentTarget.select();
copyText(shareLink);
}}
/>
<p className="mt-1 text-sm text-gray-400">
You can share the above link with anyone who has access
</p>
<div className="mt-4 flex flex-col items-center justify-end gap-2">
<button
className={cn(
'flex w-full items-center justify-center gap-1.5 rounded bg-black px-4 py-2.5 text-sm font-medium text-white hover:opacity-80',
isCopied && 'bg-green-300 text-green-800'
)}
disabled={isCopied}
onClick={() => {
copyText(shareLink);
}}
>
<Copy className="h-3.5 w-3.5 stroke-[2.5]" />
{isCopied ? 'Copied' : 'Copy'}
</button>
<button
className={cn(
'flex w-full items-center justify-center gap-1.5 rounded border border-black px-4 py-2 text-sm font-medium hover:bg-gray-100'
)}
onClick={onClose}
>
Close
</button>
</div>
</div>
);
}

@ -7,7 +7,7 @@ import {
ShareTeamMemberList, ShareTeamMemberList,
type TeamMemberList, type TeamMemberList,
} from './ShareTeamMemberList'; } from './ShareTeamMemberList';
import { CopyRoadmapLink } from './CopyRoadmapLink'; import { ShareSuccess } from './ShareSuccess';
import { useToast } from '../../hooks/use-toast'; import { useToast } from '../../hooks/use-toast';
import type { AllowedRoadmapVisibility } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal'; import type { AllowedRoadmapVisibility } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
import { httpPatch } from '../../lib/http'; import { httpPatch } from '../../lib/http';
@ -28,6 +28,7 @@ type ShareOptionsModalProps = {
sharedTeamMemberIds?: string[]; sharedTeamMemberIds?: string[];
teamId?: string; teamId?: string;
roadmapId?: string; roadmapId?: string;
description?: string;
onShareSettingsUpdate: OnShareSettingsUpdate; onShareSettingsUpdate: OnShareSettingsUpdate;
}; };
@ -41,6 +42,7 @@ export function ShareOptionsModal(props: ShareOptionsModalProps) {
sharedFriendIds: defaultSharedFriendIds = [], sharedFriendIds: defaultSharedFriendIds = [],
teamId, teamId,
onShareSettingsUpdate, onShareSettingsUpdate,
description,
} = props; } = props;
const toast = useToast(); const toast = useToast();
@ -156,7 +158,12 @@ export function ShareOptionsModal(props: ShareOptionsModalProps) {
wrapperClassName="max-w-lg" wrapperClassName="max-w-lg"
bodyClassName="p-4 flex flex-col" bodyClassName="p-4 flex flex-col"
> >
<CopyRoadmapLink roadmapId={roadmapId!} onClose={onClose} /> <ShareSuccess
visibility={visibility}
roadmapId={roadmapId!}
description={description}
onClose={onClose}
/>
</Modal> </Modal>
); );
} }

@ -0,0 +1,115 @@
import { CheckCircle, Copy, Facebook, Linkedin, Twitter } from 'lucide-react';
import { useCopyText } from '../../hooks/use-copy-text';
import { cn } from '../../lib/classname';
import type { AllowedRoadmapVisibility } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
type ShareSuccessProps = {
roadmapId: string;
onClose: () => void;
visibility: AllowedRoadmapVisibility;
description?: string;
};
export function ShareSuccess(props: ShareSuccessProps) {
const { roadmapId, onClose, description, visibility } = props;
const baseUrl = import.meta.env.DEV
? 'http://localhost:3000'
: 'https://roadmap.sh';
const shareLink = `${baseUrl}/r?id=${roadmapId}`;
const { copyText, isCopied } = useCopyText();
const socialShareLinks = [
{
title: 'Twitter',
href: `https://twitter.com/intent/tweet?text=${description}&url=${shareLink}`,
icon: Twitter,
},
{
title: 'Facebook',
href: `https://www.facebook.com/sharer/sharer.php?quote=${description}&u=${shareLink}`,
icon: Facebook,
},
{
title: 'Linkedin',
href: `https://www.linkedin.com/sharing/share-offsite/?url=${shareLink}`,
icon: Linkedin,
},
];
return (
<div className="flex grow flex-col justify-center">
<div className="mt-5 flex grow flex-col items-center justify-center gap-1.5">
<CheckCircle className="h-14 w-14 text-green-500" />
<h3 className="text-xl font-medium">Sharing Settings Updated</h3>
</div>
<input
type="text"
className="mt-6 w-full rounded-md border bg-gray-50 p-2 px-2.5 text-gray-700 focus:outline-none"
value={shareLink}
readOnly
onClick={(e) => {
e.currentTarget.select();
copyText(shareLink);
}}
/>
<p className="mt-1 text-sm text-gray-400">
You can share the above link with anyone who has access
</p>
{visibility === 'public' && (
<>
<div className="-mx-4 mt-4 flex items-center gap-1.5">
<span className="h-px grow bg-gray-300" />
<span className="text-sm uppercase text-gray-600">Or</span>
<span className="h-px grow bg-gray-300" />
</div>
<div className="mt-4 flex items-center gap-2">
<span className="text-sm text-gray-600">Share on</span>
<ul className="flex items-center gap-1.5">
{socialShareLinks.map((socialShareLink) => (
<li key={socialShareLink.title}>
<a
href={socialShareLink.href}
target="_blank"
rel="noopener noreferrer"
className="flex h-8 w-8 items-center justify-center gap-1.5 rounded-md border bg-gray-50 text-sm text-gray-700 hover:bg-gray-100 focus:outline-none"
>
<socialShareLink.icon className="h-4 w-4" />
</a>
</li>
))}
</ul>
</div>
</>
)}
<div className="mt-4 flex flex-col items-center justify-end gap-2">
<button
className={cn(
'flex w-full items-center justify-center gap-1.5 rounded bg-black px-4 py-2.5 text-sm font-medium text-white hover:opacity-80',
isCopied && 'bg-green-300 text-green-800'
)}
disabled={isCopied}
onClick={() => {
copyText(shareLink);
}}
>
<Copy className="h-3.5 w-3.5 stroke-[2.5]" />
{isCopied ? 'Copied' : 'Copy'}
</button>
<button
className={cn(
'flex w-full items-center justify-center gap-1.5 rounded border border-black px-4 py-2 text-sm font-medium hover:bg-gray-100'
)}
onClick={onClose}
>
Close
</button>
</div>
</div>
);
}

@ -311,6 +311,7 @@ export function TeamRoadmaps() {
const shareSettingsModal = selectedResource && ( const shareSettingsModal = selectedResource && (
<ShareOptionsModal <ShareOptionsModal
description={selectedResource.description!}
visibility={selectedResource.visibility!} visibility={selectedResource.visibility!}
sharedTeamMemberIds={selectedResource.sharedTeamMemberIds!} sharedTeamMemberIds={selectedResource.sharedTeamMemberIds!}
sharedFriendIds={selectedResource.sharedFriendIds!} sharedFriendIds={selectedResource.sharedFriendIds!}

Loading…
Cancel
Save