feat: add session sharing types, API client, and utilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import apiClient from './client'
|
import apiClient from './client'
|
||||||
import type { Session, SessionCreate, SessionUpdate, SessionExport, SaveAsTreeRequest, SaveAsTreeResponse, SessionComplete, RedactionSummary } from '@/types'
|
import type { Session, SessionCreate, SessionUpdate, SessionExport, SaveAsTreeRequest, SaveAsTreeResponse, SessionComplete, RedactionSummary, SessionShareCreate, SessionShare, SharedSessionView } from '@/types'
|
||||||
|
|
||||||
export interface SessionListParams {
|
export interface SessionListParams {
|
||||||
page?: number
|
page?: number
|
||||||
@@ -85,6 +85,26 @@ export const sessionsApi = {
|
|||||||
const response = await apiClient.post<SaveAsTreeResponse>(`/sessions/${id}/save-as-tree`, data)
|
const response = await apiClient.post<SaveAsTreeResponse>(`/sessions/${id}/save-as-tree`, data)
|
||||||
return response.data
|
return response.data
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Session Sharing
|
||||||
|
async createShare(sessionId: string, data: SessionShareCreate): Promise<SessionShare> {
|
||||||
|
const response = await apiClient.post<SessionShare>(`/sessions/${sessionId}/shares`, data)
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
|
||||||
|
async listMyShares(): Promise<SessionShare[]> {
|
||||||
|
const response = await apiClient.get<SessionShare[]>('/shares/my-shares')
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
|
||||||
|
async revokeShare(shareId: string): Promise<void> {
|
||||||
|
await apiClient.delete(`/shares/${shareId}`)
|
||||||
|
},
|
||||||
|
|
||||||
|
async getSharedSession(shareToken: string): Promise<SharedSessionView> {
|
||||||
|
const response = await apiClient.get<SharedSessionView>(`/share/${shareToken}`)
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default sessionsApi
|
export default sessionsApi
|
||||||
|
|||||||
27
frontend/src/lib/sessionShare.ts
Normal file
27
frontend/src/lib/sessionShare.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import type { SessionShare } from '@/types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the full share URL from a SessionShare object.
|
||||||
|
* Uses share.share_url if present, otherwise constructs from token.
|
||||||
|
*/
|
||||||
|
export function buildSessionShareUrl(share: SessionShare): string {
|
||||||
|
if (share.share_url) return share.share_url
|
||||||
|
return `${window.location.origin}/share/${share.share_token}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter shares to only those belonging to a specific session.
|
||||||
|
*/
|
||||||
|
export function filterSharesForSession(shares: SessionShare[], sessionId: string): SessionShare[] {
|
||||||
|
return shares.filter(s => s.session_id === sessionId && s.is_active)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the most recent active share for a given session.
|
||||||
|
* Returns null if no active shares exist.
|
||||||
|
*/
|
||||||
|
export function getLatestActiveShareForSession(shares: SessionShare[], sessionId: string): SessionShare | null {
|
||||||
|
const sessionShares = filterSharesForSession(shares, sessionId)
|
||||||
|
if (sessionShares.length === 0) return null
|
||||||
|
return sessionShares.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0]
|
||||||
|
}
|
||||||
@@ -125,3 +125,45 @@ export interface SaveAsTreeResponse {
|
|||||||
tree_name: string
|
tree_name: string
|
||||||
message: string
|
message: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Session Sharing
|
||||||
|
export type SessionShareVisibility = 'public' | 'account'
|
||||||
|
|
||||||
|
export interface SessionShareCreate {
|
||||||
|
visibility: SessionShareVisibility
|
||||||
|
share_name?: string
|
||||||
|
expires_at?: string // ISO datetime string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SessionShare {
|
||||||
|
id: string
|
||||||
|
session_id: string
|
||||||
|
account_id: string
|
||||||
|
share_token: string
|
||||||
|
share_name: string | null
|
||||||
|
visibility: SessionShareVisibility
|
||||||
|
created_by: string
|
||||||
|
created_at: string
|
||||||
|
updated_at: string
|
||||||
|
expires_at: string | null
|
||||||
|
view_count: number
|
||||||
|
last_viewed_at: string | null
|
||||||
|
is_active: boolean
|
||||||
|
share_url: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SharedSessionView {
|
||||||
|
session_id: string
|
||||||
|
tree_name: string
|
||||||
|
tree_description: string | null
|
||||||
|
tree_structure: Record<string, unknown>
|
||||||
|
path_taken: string[]
|
||||||
|
decisions: DecisionRecord[]
|
||||||
|
custom_steps: CustomStep[]
|
||||||
|
started_at: string
|
||||||
|
completed_at: string | null
|
||||||
|
ticket_number: string | null
|
||||||
|
client_name: string | null
|
||||||
|
share_name: string | null
|
||||||
|
visibility: SessionShareVisibility
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user