feat: add participant interview link action
Add a copy button to scheduled interview sessions with confirmation, clipboard error handling, and regression coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
afc8f0d5a7
commit
e4fee06e2f
2 changed files with 27 additions and 1 deletions
|
|
@ -814,6 +814,7 @@ describe('Go Guess frontend', () => {
|
|||
it('edits shared documentation and displays notes received over authenticated fetch streaming', async () => {
|
||||
authenticate()
|
||||
const user = userEvent.setup()
|
||||
const writeText = vi.spyOn(navigator.clipboard, 'writeText')
|
||||
const scheduled = {
|
||||
id: 80,
|
||||
jobId: 7,
|
||||
|
|
@ -866,6 +867,11 @@ describe('Go Guess frontend', () => {
|
|||
})
|
||||
renderApp('/scheduled-interviews/80')
|
||||
expect(await screen.findByText('Strong system design answer.')).toBeInTheDocument()
|
||||
await user.click(screen.getByRole('button', { name: 'Copy participant interview link' }))
|
||||
expect(writeText).toHaveBeenCalledWith('/participant/meeting/meeting-token')
|
||||
expect(
|
||||
screen.getByRole('button', { name: 'Copy participant interview link' }),
|
||||
).toHaveTextContent('Link copied')
|
||||
const document = screen.getByLabelText('Shared documentation')
|
||||
await user.clear(document)
|
||||
await user.type(document, 'Updated candidate exercise')
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Check, UsersRound, X } from 'lucide-react'
|
||||
import { Check, Copy, UsersRound, X } from 'lucide-react'
|
||||
import { type FormEvent, useEffect, useMemo, useState } from 'react'
|
||||
import { Link, useParams } from 'react-router-dom'
|
||||
import { api, ApiError } from '../../api/client'
|
||||
|
|
@ -145,6 +145,7 @@ export function ScheduledInterviewPage() {
|
|||
const [notes, setNotes] = useState<ScheduledInterview['notes']>([])
|
||||
const [error, setError] = useState('')
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [linkCopied, setLinkCopied] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
let active = true
|
||||
|
|
@ -218,6 +219,16 @@ export function ScheduledInterviewPage() {
|
|||
}
|
||||
}
|
||||
|
||||
async function copyParticipantLink(url: string) {
|
||||
setError('')
|
||||
try {
|
||||
await navigator.clipboard.writeText(url)
|
||||
setLinkCopied(true)
|
||||
} catch {
|
||||
setError('Could not copy the participant interview link')
|
||||
}
|
||||
}
|
||||
|
||||
if (!interview && !error) return <Loading />
|
||||
if (!interview) return <ErrorAlert error={error} />
|
||||
return (
|
||||
|
|
@ -236,6 +247,15 @@ export function ScheduledInterviewPage() {
|
|||
{error && <ErrorAlert error={error} />}
|
||||
<DateAndPlace interview={interview} />
|
||||
<div className="session-actions">
|
||||
<button
|
||||
className="button secondary"
|
||||
type="button"
|
||||
onClick={() => void copyParticipantLink(interview.candidateUrl)}
|
||||
aria-label="Copy participant interview link"
|
||||
>
|
||||
{linkCopied ? <Check size={17} /> : <Copy size={17} />}
|
||||
{linkCopied ? 'Link copied' : 'Copy participant link'}
|
||||
</button>
|
||||
{interview.status !== 'started' && interview.status !== 'completed' && (
|
||||
<button
|
||||
className="button primary"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue