Skip to content

Commit 403e5de

Browse files
committed
feat(admin): add copy direct link button to showcase page
Lets admins copy the public /demo/:slug URL for a showcase directly from the showcase editor header. Signed-off-by: Emiliano Suñé <2395873+esune@users.noreply.github.com>
1 parent 1273577 commit 403e5de

2 files changed

Lines changed: 29 additions & 2 deletions

File tree

frontend/src/admin/pages/ShowcasePage.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { UserIcon, QueueListIcon, FilmIcon, ArrowLeftIcon } from '@heroicons/react/24/outline'
1+
import { UserIcon, QueueListIcon, FilmIcon, ArrowLeftIcon, LinkIcon } from '@heroicons/react/24/outline'
22
import { useEffect, useState } from 'react'
33
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom'
44

5+
import { basePath as clientBasePath } from '../../client/utils/BasePath'
56
import { adminBaseRoute } from '../api/adminApi'
67
import { AdminNavbar } from '../components/AdminNavbar'
78
import { SecondaryNavbar } from '../components/showcase/SecondaryNavbar'
@@ -25,6 +26,7 @@ export function ShowcasePage() {
2526
const { showcase, isLoading, refetch } = useShowcase()
2627
const [isExpanded, setIsExpanded] = useState(false)
2728
const [isNewShowcase, setIsNewShowcase] = useState(location.state?.isNewShowcase || false)
29+
const [linkCopied, setLinkCopied] = useState(false)
2830
const tabFromUrl = searchParams.get('tab')
2931
const [activeTab, setActiveTab] = useState<TabId>(isValidTabId(tabFromUrl) ? tabFromUrl : 'persona')
3032

@@ -57,6 +59,18 @@ export function ShowcasePage() {
5759
navigate(`${adminBaseRoute}/creator`)
5860
}
5961

62+
const handleCopyDirectLink = () => {
63+
if (!showcase?.slug) return
64+
const directLink = `${window.location.origin}${clientBasePath}/demo/${showcase.slug}`
65+
navigator.clipboard
66+
.writeText(directLink)
67+
.then(() => {
68+
setLinkCopied(true)
69+
setTimeout(() => setLinkCopied(false), 2000)
70+
})
71+
.catch(() => undefined)
72+
}
73+
6074
return (
6175
<div className="flex flex-col h-screen bg-gray-50">
6276
<AdminNavbar onLogoClick={handleLogoClick} />
@@ -71,7 +85,19 @@ export function ShowcasePage() {
7185
<span className="font-medium">Back to Showcases</span>
7286
</button>
7387
<div className="w-full max-w-4xl">
74-
<h2 className="text-2xl font-semibold text-bcgov-black">{showcase?.name || 'Showcase Name'}</h2>
88+
<div className="flex items-center gap-2">
89+
<h2 className="text-2xl font-semibold text-bcgov-black">{showcase?.name || 'Showcase Name'}</h2>
90+
{showcase?.slug && (
91+
<button
92+
onClick={handleCopyDirectLink}
93+
title="Copy direct link"
94+
className="text-gray-400 hover:text-bcgov-blue transition-all p-1 rounded"
95+
>
96+
<LinkIcon className="w-5 h-5" />
97+
</button>
98+
)}
99+
{linkCopied && <span className="text-sm text-bcgov-blue">Copied!</span>}
100+
</div>
75101
<h5 className="text-gray-500 mt-2">{showcase?.description || 'Description of the showcase.'}</h5>
76102
</div>
77103
</div>

frontend/src/admin/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export type ShowcaseStatus = 'active' | 'hidden' | 'pending'
9999

100100
export interface Showcase {
101101
name: string
102+
slug?: string
102103
status?: ShowcaseStatus
103104
deleted_at?: string | null
104105
description?: string

0 commit comments

Comments
 (0)