From 0046af16c2633bf8dc6d800bbbeac4ae10c32004 Mon Sep 17 00:00:00 2001 From: Brian Lovin Date: Wed, 4 Aug 2021 20:11:43 -0700 Subject: [PATCH 1/3] Prevent two audio players from playing at the same time --- src/components/AudioPlayer/Waveform.tsx | 2 +- src/components/AudioPlayer/index.tsx | 33 +++++++++++++++++++++---- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/components/AudioPlayer/Waveform.tsx b/src/components/AudioPlayer/Waveform.tsx index b34bf8fb0..b815e6fa3 100644 --- a/src/components/AudioPlayer/Waveform.tsx +++ b/src/components/AudioPlayer/Waveform.tsx @@ -85,7 +85,7 @@ export default function Waveform({ return ( ) diff --git a/src/components/AudioPlayer/index.tsx b/src/components/AudioPlayer/index.tsx index 5005af64b..3113ecdd0 100644 --- a/src/components/AudioPlayer/index.tsx +++ b/src/components/AudioPlayer/index.tsx @@ -32,11 +32,15 @@ export default function AudioPlayer({ React.useEffect(() => { resetProgressOverlay() - audioRef.current.addEventListener('ended', function () { - audioRef.current.currentTime = 0 - resetProgressOverlay() - setIsPlaying(false) - }) + audioRef.current.addEventListener('play', onAudioElementPlay) + audioRef.current.addEventListener('pause', onAudioElementPause) + audioRef.current.addEventListener('ended', onAudioElementEnded) + + return function cleanupListeners() { + audioRef.current.removeEventListener('play', onAudioElementPlay) + audioRef.current.removeEventListener('pause', onAudioElementPause) + audioRef.current.removeEventListener('ended', onAudioElementEnded) + } }, []) function pause() { @@ -69,7 +73,26 @@ export default function AudioPlayer({ setIsPlaying(true) } + function onAudioElementEnded() { + audioRef.current.currentTime = 0 + resetProgressOverlay() + setIsPlaying(false) + } + + function onAudioElementPlay() { + setIsPlaying(true) + } + + function onAudioElementPause() { + setIsPlaying(false) + } + function togglePlay() { + // pause all other audio players + const audios = document.querySelectorAll('audio') + audios.forEach((audio) => audio.pause()) + + // pause or play this audio player isPlaying ? pause() : play() } From 901ac50b05342365644e9e07f923d2d16b07dced Mon Sep 17 00:00:00 2001 From: Brian Lovin Date: Wed, 4 Aug 2021 20:20:09 -0700 Subject: [PATCH 2/3] Fix reactions returning inaccurate question data --- src/components/AudioPlayer/index.tsx | 6 ++-- src/graphql/helpers/sanitizeAmaDocument.ts | 35 ++++++++++++++++++++ src/graphql/resolvers/mutations/ama/index.ts | 6 ++-- src/graphql/resolvers/queries/ama/index.ts | 16 +++------ 4 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 src/graphql/helpers/sanitizeAmaDocument.ts diff --git a/src/components/AudioPlayer/index.tsx b/src/components/AudioPlayer/index.tsx index 3113ecdd0..c9b463c7f 100644 --- a/src/components/AudioPlayer/index.tsx +++ b/src/components/AudioPlayer/index.tsx @@ -37,9 +37,9 @@ export default function AudioPlayer({ audioRef.current.addEventListener('ended', onAudioElementEnded) return function cleanupListeners() { - audioRef.current.removeEventListener('play', onAudioElementPlay) - audioRef.current.removeEventListener('pause', onAudioElementPause) - audioRef.current.removeEventListener('ended', onAudioElementEnded) + audioRef?.current?.removeEventListener('play', onAudioElementPlay) + audioRef?.current?.removeEventListener('pause', onAudioElementPause) + audioRef?.current?.removeEventListener('ended', onAudioElementEnded) } }, []) diff --git a/src/graphql/helpers/sanitizeAmaDocument.ts b/src/graphql/helpers/sanitizeAmaDocument.ts new file mode 100644 index 000000000..682bcb87f --- /dev/null +++ b/src/graphql/helpers/sanitizeAmaDocument.ts @@ -0,0 +1,35 @@ +import { storage } from '~/graphql/services/firebase' +import { AUDIO_STORAGE_BUCKET } from '../constants' + +async function fetchAudioPlaybackUrl(id) { + const bucket = storage.bucket(AUDIO_STORAGE_BUCKET) + const url = await bucket + .file(id) + .getSignedUrl({ + expires: Date.now() + 60 * 60 * 1000, // one hour + action: 'read', + }) + .then((r) => r[0]) + .catch((e) => { + console.error({ e }) + return null + }) + return await Promise.resolve(url) +} + +export async function sanitizeAmaDocument(document, id) { + const createdAt = document.createdAt.toDate() + const updatedAt = document.updatedAt.toDate() + const audioUrl = + document.audioWaveform?.length > 0 ? await fetchAudioPlaybackUrl(id) : null + const audioPlayCount = document.audioPlayCount || 0 + const audioWaveform = document.audioWaveform || [] + + return { + createdAt, + updatedAt, + audioWaveform, + audioUrl, + audioPlayCount, + } +} diff --git a/src/graphql/resolvers/mutations/ama/index.ts b/src/graphql/resolvers/mutations/ama/index.ts index f23577953..111f098cf 100644 --- a/src/graphql/resolvers/mutations/ama/index.ts +++ b/src/graphql/resolvers/mutations/ama/index.ts @@ -9,6 +9,7 @@ import { MutationEditAmaQuestionArgs, MutationTranscribeAudioArgs, } from '~/graphql/types.generated' +import { sanitizeAmaDocument } from '~/graphql/helpers/sanitizeAmaDocument' const COLLECTION = IS_PROD ? 'questions' : 'questions-dev' @@ -70,9 +71,8 @@ export async function addAMAReaction(_, { id }) { }) const res = await docRef.get().then((doc) => doc.data()) - const createdAt = res.createdAt.toDate() - const updatedAt = res.updatedAt.toDate() - return { ...res, createdAt, updatedAt, id } + const sanitizedAmaDocument = await sanitizeAmaDocument(doc, id) + return { ...res, id, ...sanitizedAmaDocument } } export async function addAMAAudioPlay(_, { id }) { diff --git a/src/graphql/resolvers/queries/ama/index.ts b/src/graphql/resolvers/queries/ama/index.ts index c41b87f14..420b1a0e2 100644 --- a/src/graphql/resolvers/queries/ama/index.ts +++ b/src/graphql/resolvers/queries/ama/index.ts @@ -11,6 +11,7 @@ import { IS_PROD, PAGINATION_AMOUNT, } from '~/graphql/constants' +import { sanitizeAmaDocument } from '~/graphql/helpers/sanitizeAmaDocument' async function fetchAudioPlaybackUrl(id) { const bucket = storage.bucket(AUDIO_STORAGE_BUCKET) @@ -51,20 +52,13 @@ export async function getAMAQuestions( for (let question of questionsRef.docs) { const d = question.data() const id = question.id - const createdAt = d.createdAt.toDate() - const updatedAt = d.updatedAt.toDate() - const audioUrl = - d.audioWaveform?.length > 0 ? await fetchAudioPlaybackUrl(id) : null - const audioPlayCount = d.audioPlayCount || 0 - const audioWaveform = d.audioWaveform || [] + + const sanitizedAmaDocument = await sanitizeAmaDocument(d, id) + const record = { ...d, id, - createdAt, - updatedAt, - audioUrl, - audioPlayCount, - audioWaveform, + ...sanitizedAmaDocument, } as Ama data.push(record) From c46d7092a87da81a88dac4d79def5d434102134e Mon Sep 17 00:00:00 2001 From: Brian Lovin Date: Wed, 4 Aug 2021 20:26:56 -0700 Subject: [PATCH 3/3] Fetch latest questions on each request --- src/graphql/constants/index.ts | 4 +++- src/graphql/resolvers/mutations/ama/index.ts | 15 ++++++--------- src/graphql/resolvers/queries/ama/index.ts | 5 ++--- src/pages/ama.tsx | 5 ++--- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/graphql/constants/index.ts b/src/graphql/constants/index.ts index df721dcf6..87f1969d1 100644 --- a/src/graphql/constants/index.ts +++ b/src/graphql/constants/index.ts @@ -2,5 +2,7 @@ import { baseUrl } from '~/config/seo' export const IS_PROD = process.env.NODE_ENV === 'production' export const CLIENT_URL = IS_PROD ? baseUrl : 'http://localhost:3000' -export const AUDIO_STORAGE_BUCKET = IS_PROD ? 'audio-ama' : 'audio-ama-dev' export const PAGINATION_AMOUNT = 16 + +export const AUDIO_STORAGE_BUCKET = IS_PROD ? 'audio-ama' : 'audio-ama-dev' +export const AMA_QUESTIONS_COLLECTION = IS_PROD ? 'questions' : 'questions-dev' diff --git a/src/graphql/resolvers/mutations/ama/index.ts b/src/graphql/resolvers/mutations/ama/index.ts index 111f098cf..1028f7606 100644 --- a/src/graphql/resolvers/mutations/ama/index.ts +++ b/src/graphql/resolvers/mutations/ama/index.ts @@ -1,5 +1,5 @@ import { baseUrl } from '~/config/seo' -import { IS_PROD } from '~/graphql/constants' +import { AMA_QUESTIONS_COLLECTION, IS_PROD } from '~/graphql/constants' import { db } from '~/graphql/services/firebase' import { emailMe } from '~/graphql/services/postmark' import fetch from 'node-fetch' @@ -11,11 +11,9 @@ import { } from '~/graphql/types.generated' import { sanitizeAmaDocument } from '~/graphql/helpers/sanitizeAmaDocument' -const COLLECTION = IS_PROD ? 'questions' : 'questions-dev' - export async function editAMAQuestion(_, args: MutationEditAmaQuestionArgs) { const { id, question, answer, status, audioWaveform } = args - const docRef = db.collection(COLLECTION).doc(id) + const docRef = db.collection(AMA_QUESTIONS_COLLECTION).doc(id) await docRef.update({ question, answer, @@ -40,7 +38,7 @@ export async function addAMAQuestion( }) return await db - .collection(COLLECTION) + .collection(AMA_QUESTIONS_COLLECTION) .add({ question, answer: null, @@ -56,12 +54,12 @@ export async function deleteAMAQuestion( _, { id }: MutationDeleteAmaQuestionArgs ) { - const docRef = db.collection(COLLECTION).doc(id) + const docRef = db.collection(AMA_QUESTIONS_COLLECTION).doc(id) return await docRef.delete().then(() => true) } export async function addAMAReaction(_, { id }) { - const docRef = db.collection(COLLECTION).doc(id) + const docRef = db.collection(AMA_QUESTIONS_COLLECTION).doc(id) const doc = await docRef.get().then((doc) => doc.data()) const count = doc.reactions ? doc.reactions + 1 : 1 @@ -76,9 +74,8 @@ export async function addAMAReaction(_, { id }) { } export async function addAMAAudioPlay(_, { id }) { - const docRef = db.collection(COLLECTION).doc(id) + const docRef = db.collection(AMA_QUESTIONS_COLLECTION).doc(id) const doc = await docRef.get().then((doc) => doc.data()) - const count = doc.playCount ? doc.playCount + 1 : 1 await docRef.update({ diff --git a/src/graphql/resolvers/queries/ama/index.ts b/src/graphql/resolvers/queries/ama/index.ts index 420b1a0e2..d34136827 100644 --- a/src/graphql/resolvers/queries/ama/index.ts +++ b/src/graphql/resolvers/queries/ama/index.ts @@ -7,8 +7,8 @@ import { QueryTranscriptionArgs, } from '~/graphql/types.generated' import { + AMA_QUESTIONS_COLLECTION, AUDIO_STORAGE_BUCKET, - IS_PROD, PAGINATION_AMOUNT, } from '~/graphql/constants' import { sanitizeAmaDocument } from '~/graphql/helpers/sanitizeAmaDocument' @@ -34,7 +34,6 @@ export async function getAMAQuestions( args: QueryAmaQuestionsArgs, { isMe } ) { - const COLLECTION = IS_PROD ? 'questions' : 'questions-dev' const { skip = 0, status = 'ANSWERED' } = args if (status === 'PENDING' && !isMe) return [] @@ -42,7 +41,7 @@ export async function getAMAQuestions( const data = [] async function processQuestions() { - let collection = db.collection(COLLECTION) + let collection = db.collection(AMA_QUESTIONS_COLLECTION) let questionsRef = await collection .where('status', '==', status) .orderBy('updatedAt', 'desc') diff --git a/src/pages/ama.tsx b/src/pages/ama.tsx index 3171755b3..5ce1d85a9 100644 --- a/src/pages/ama.tsx +++ b/src/pages/ama.tsx @@ -20,7 +20,7 @@ function About() { /> -