import ApiClient from './ApiClient'; import * as P from './types/Presentation'; import urls from './urls'; import { mapResourceResponse, mapResourceV2Response, mapCreateTag, } from './ResourceClient'; import { mapFileUploadResponse, mapNewFileUploadsResponse, } from './FileUploadUtils'; import { mapThemeResponse } from './ThemeClient'; export const mapPresentationResponse = ( p: P.PresentationResponse, ): P.Presentation => ({ id: p.id, name: p.name, applicationId: p.application_id, appVersionId: p.application_deployment_id, themeId: p.theme_id, applicationThumbnailUrl: p.application_thumbnail_url, thumbnailUrl: p.thumbnail_url, iconUrl: p.icon_url, applicationName: p.application_name, presentationProperties: p.presentation_properties, applicationVariables: p.application_vars, hasDynamicThumbnails: p.has_dynamic_thumbnails, duration: p.duration, sourceUrl: p.source_url, fileUploads: p.file_uploads ? p.file_uploads.map(mapFileUploadResponse) : null, resource: mapResourceResponse(p.resource), theme: p.theme_id && p.theme ? mapThemeResponse({ ...p.theme, resource: p.resource, }) : undefined, previewOrientation: p.preview_orientation, previewResolution: p.preview_resolution, }); export const mapPresentationV2Response = ( p: P.PresentationV2Response, ): P.PresentationV2 => ({ id: p.id, name: p.name, duration: p.duration, applicationVariables: p.application_vars, applicationDeploymentId: p.application_deployment_id, themeId: p.theme_id, token: p.token, r: { resource: mapResourceV2Response(p.r.resource), presentationsPlaylists: (p.r.presentations_playlists || []).map((item) => ({ playlistId: item.playlist_id, })), }, previewOrientation: p.preview_orientation, previewResolution: p.preview_resolution, }); export const mapPresentationToV2 = (p: P.Presentation): P.PresentationV2 => ({ id: p.id, name: p.name, duration: p.duration ?? 30, applicationVariables: p.applicationVariables, applicationDeploymentId: p.appVersionId, themeId: p.themeId ?? null, token: p.token, r: { resource: { id: p.resource.id, profileId: p.resource.profile.id, domainId: p.resource.domain?.id ?? null, parentFolderId: p.resource.parentFolderId, createdAt: p.resource.createdAt, updatedAt: p.resource.updatedAt, deletedAt: p.resource.deletedAt, r: { tags: p.resource.r.tags, }, }, presentationsPlaylists: [], }, }); export default class PresentationClient { async getPresentations( this: ApiClient, filter?: { ids: string[] }, ): Promise { const isValidQueryParams = filter && filter.ids.length > 0; const filterQs = isValidQueryParams ? `?id=${filter?.ids.join(',')}` : ''; const data = await this.requestProtected< P.GetPresentationsRequest, P.GetPresentationsResponse >({ method: 'GET', url: `${urls.presentations()}${filterQs}`, }); return data.map(mapPresentationResponse); } async deletePresentation(this: ApiClient, id: string): Promise { await this.requestProtected< P.DeletePresentationRequest, P.DeletePresentationResponse >({ method: 'DELETE', url: urls.presentation(id), }); } async updatePresentation( this: ApiClient, id: string, params: P.UpdatePresentation, ): Promise<[P.Presentation, P.NewFileUploads]> { const { presentation, file_uploads: fileUploads, } = await this.requestProtected< P.UpdatePresentationRequest, P.UpdatePresentationResponse >({ method: 'PATCH', url: urls.presentation(id), body: { name: params.name, application_deployment_id: params.appVersionId, theme_id: params.themeId, application_vars: params.applicationVariables, duration: params.duration, resource: params.resource && { r: params.resource?.r && { tags: params.resource.r.tags?.map(mapCreateTag), }, }, preview_orientation: params.previewOrientation, preview_resolution: params.previewResolution, }, }); return [ mapPresentationResponse(presentation), mapNewFileUploadsResponse(fileUploads), ]; } async createPresentation( this: ApiClient, params: P.CreatePresentation, ): Promise<[P.Presentation, P.NewFileUploads]> { const { presentation, file_uploads: fileUploads, } = await this.requestProtected< P.CreatePresentationRequest, P.CreatePresentationResponse >({ method: 'POST', url: urls.presentations(), body: { name: params.name, application_deployment_id: params.appVersionId, theme_id: params.themeId, application_vars: params.applicationVariables, duration: params.duration, preview_orientation: params.previewOrientation, preview_resolution: params.previewResolution, }, }); return [ mapPresentationResponse(presentation), mapNewFileUploadsResponse(fileUploads), ]; } async movePresentationToFolder( this: ApiClient, presentationId: string, folderId: string | null, ): Promise { await this.requestProtected<{ folder_id: string | null }, void>({ method: 'POST', url: urls.presentationMoveToFolder(presentationId), body: { folder_id: folderId, }, }); } async copyPresentation( this: ApiClient, presentationId: string, params: { name?: string; targetFolderId?: string; copyOutOfTreeUnowned?: boolean; } = {}, ): Promise { const data = await this.requestProtected< P.CopyPresentationRequest, P.CopyPresentationResponse >({ method: 'POST', url: urls.presentationCopy(presentationId), body: { name: params.name, ...(params.targetFolderId ? { target_folder_id: params.targetFolderId } : {}), ...(params.copyOutOfTreeUnowned !== undefined ? { copy_out_of_tree_unowned: params.copyOutOfTreeUnowned } : {}), }, }); // Preflight: when the server flags out-of-tree unowned content it copies // nothing and returns only the flag (no presentation — so no `id` — to // map), so short-circuit. A confirmed copy always returns the presentation // (even if it echoes the flag), so the `'id' in data` guard keeps it on the // real branch. if (!('id' in data)) { return { hasOutOfTreeUnowned: true, supportingContentFolderCreated: false, }; } return { ...mapPresentationResponse(data), supportingContentFolderCreated: !!data.supporting_content_folder_created, }; } async getPresentationsList( this: ApiClient, query?: string, ): Promise { const data = await this.requestProtected< P.GetPresentationsRequest, P.GetPresentationsListResponse >({ method: 'GET', url: urls.getPresentationsList(query), }); return data; } }