diff --git a/nextjs/src/lib/config.js b/nextjs/src/lib/config.js new file mode 100644 index 0000000..175d627 --- /dev/null +++ b/nextjs/src/lib/config.js @@ -0,0 +1,18 @@ +export const config = { + /** + * Find your project ID and dataset in `sanity.json` in your studio project. + * These are considered β€œpublic”, but you can use environment variables + * if you want differ between local dev and production. + * + * https://nextjs.org/docs/basic-features/environment-variables + * */ + dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || 'production', + projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID, + apiVersion: '2021-03-25', + /** + * Set useCdn to `false` if your application require the freshest possible + * data always (potentially slightly slower and a bit more expensive). + * Authenticated request (like preview) will always bypass the CDN + * */ + useCdn: process.env.NODE_ENV === 'production', +}; diff --git a/nextjs/src/lib/sanity.js b/nextjs/src/lib/sanity.js new file mode 100644 index 0000000..6f4f8c5 --- /dev/null +++ b/nextjs/src/lib/sanity.js @@ -0,0 +1,28 @@ +// lib/sanity.js +import { + createImageUrlBuilder, + createPortableTextComponent, + createPreviewSubscriptionHook, + createCurrentUserHook, +} from 'next-sanity'; +import { config } from './config'; + +/** + * Set up a helper function for generating Image URLs with only the asset reference data in your documents. + * Read more: https://www.sanity.io/docs/image-url + * */ +export const urlFor = (source) => createImageUrlBuilder(config).image(source); + +// Set up the live preview subscription hook +export const usePreviewSubscription = createPreviewSubscriptionHook(config); + +// Set up Portable Text serialization +export const PortableText = createPortableTextComponent({ + ...config, + // Serializers passed to @sanity/block-content-to-react + // (https://github.com/sanity-io/block-content-to-react) + serializers: {}, +}); + +// Helper function for using the current logged in user account +export const useCurrentUser = createCurrentUserHook(config); diff --git a/nextjs/src/lib/sanity.server.js b/nextjs/src/lib/sanity.server.js new file mode 100644 index 0000000..703e240 --- /dev/null +++ b/nextjs/src/lib/sanity.server.js @@ -0,0 +1,32 @@ +// lib/sanity.server.js +import { createClient } from 'next-sanity'; +import { config } from './config'; + +// Set up the client for fetching data in the getProps page functions +export const sanityClient = createClient(config); + +// Set up a preview client with serverless authentication for drafts +export const previewClient = createClient({ + ...config, + useCdn: false, + token: process.env.SANITY_API_TOKEN, +}); + +// Helper function for easily switching between normal client and preview client +export const getClient = (usePreview) => (usePreview ? previewClient : sanityClient); + +// taken from: https://github.com/vercel/next.js/blob/canary/examples/cms-sanity/lib/sanity.server.js +export function overlayDrafts(docs) { + const documents = docs || []; + const overlayed = documents.reduce((map, doc) => { + if (!doc._id) { + throw new Error('Ensure that `_id` is included in query projection'); + } + + const isDraft = doc._id.startsWith('drafts.'); + const id = isDraft ? doc._id.slice(7) : doc._id; + return isDraft || !map.has(id) ? map.set(id, doc) : map; + }, new Map()); + + return Array.from(overlayed.values()); +} diff --git a/nextjs/src/modules/episodes/IndividualEpisodePage.js b/nextjs/src/modules/episodes/IndividualEpisodePage.js index 8f289b4..fe94669 100644 --- a/nextjs/src/modules/episodes/IndividualEpisodePage.js +++ b/nextjs/src/modules/episodes/IndividualEpisodePage.js @@ -1,4 +1,5 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import { useRouter } from 'next/router'; import PropTypes from 'prop-types'; import styled from 'styled-components'; import { Breakpoints } from 'styles/Breakpoints'; @@ -34,12 +35,33 @@ const IndividualEpisodePage = ({ }) => { // state const [skipTo, setSkipTo] = useState(null); + const [play, setPlay] = useState(false); + const router = useRouter(); // jump to a specific time on the waveform player const skipToTimestamp = (time) => { + console.log(time); setSkipTo(time); }; + const skipToJumpLinkTimestamp = (time) => { + skipToTimestamp(time); + setPlay(true); + }; + + useEffect(() => { + const UrlParams = router.query; + const timeStr = UrlParams.time; + const time = Number(timeStr); + + if (!Number.isNaN(time)) { + console.log('Set skip time'); + skipToTimestamp(time); + } else { + skipToTimestamp(0); + } + }, [router]); + return ( @@ -67,7 +90,9 @@ const IndividualEpisodePage = ({
{/* TIME JUMP LINKS */} - {timeJump && } + {timeJump && ( + + )} {/* SHOW LINKS */} {listLink && } diff --git a/nextjs/src/modules/episodes/components/JumpLinks.js b/nextjs/src/modules/episodes/components/JumpLinks.js index 98c4a18..a6ee93f 100644 --- a/nextjs/src/modules/episodes/components/JumpLinks.js +++ b/nextjs/src/modules/episodes/components/JumpLinks.js @@ -9,10 +9,10 @@ import { MixinBodyCopy, MixinHeading } from 'styles/Typography'; /** ------------------------------------------------- * COMPONENT ---------------------------------------------------- */ -const JumpLinks = ({ className, timeJump, handleClick }) => { - const onClick = (e, time) => { +const JumpLinks = ({ className, timeJump, skipToTimestamp }) => { + const handleClick = (e, time) => { e.preventDefault(); - handleClick(time); + skipToTimestamp(Number(time)); }; return ( @@ -22,7 +22,7 @@ const JumpLinks = ({ className, timeJump, handleClick }) => { {timeJump && timeJump.map((one) => (
  • - diff --git a/nextjs/src/modules/home/components/FeaturedEpisode.js b/nextjs/src/modules/home/components/FeaturedEpisode.js index 2047763..17dadc4 100644 --- a/nextjs/src/modules/home/components/FeaturedEpisode.js +++ b/nextjs/src/modules/home/components/FeaturedEpisode.js @@ -79,11 +79,13 @@ FeaturedEpisode.propTypes = { title: PropTypes.string, briefDescription: PropTypes.string, cover: PropTypes.string, - guest: PropTypes.shape({ - avatar: PropTypes.string, - firstName: PropTypes.string, - lastName: PropTypes.string, - }), + guest: PropTypes.arrayOf( + PropTypes.shape({ + avatar: PropTypes.string, + firstName: PropTypes.string, + lastName: PropTypes.string, + }) + ), }), }; diff --git a/nextjs/src/modules/shared/components/AudioPlayer/WaveformPlayer.js b/nextjs/src/modules/shared/components/AudioPlayer/WaveformPlayer.js index f4a80bc..018e78d 100644 --- a/nextjs/src/modules/shared/components/AudioPlayer/WaveformPlayer.js +++ b/nextjs/src/modules/shared/components/AudioPlayer/WaveformPlayer.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import { useRef } from 'react'; +import { useEffect, useRef } from 'react'; import styled from 'styled-components'; // styles @@ -17,7 +17,14 @@ import { useAudioPlayer } from './hooks/AudioPlayer'; /** ------------------------------------------------- * COMPONENT ---------------------------------------------------- */ -const WaveformPlayer = ({ artwork = '/images/podcast-cover.jpg', audioPath, episodeNumber, episodeTitle }) => { +const WaveformPlayer = ({ + artwork = '/images/podcast-cover.jpg', + audioPath, + episodeNumber, + episodeTitle, + skipTo, + play = false, +}) => { // references const audioPlayer = useRef(); // set up reference for the audio component const progressBar = useRef(); // reference for the progress bar @@ -32,20 +39,24 @@ const WaveformPlayer = ({ artwork = '/images/podcast-cover.jpg', audioPath, epis forwardThirty, isPlaying, onLoadedMetadata, - // skipToTime, + skipToTime, speed, tapSpaceBar, togglePlaying, } = useAudioPlayer(audioPlayer, progressBar); - // useEffect(() => { - // skipToTime(skipTo); - // }, [skipTo]); + useEffect(() => { + skipToTime(skipTo); + if (play && !isPlaying) { + togglePlaying(); + } + //! removing skipToTime as a dependency is causing unnecessary re-renders + }, [skipTo, play]); return ( {/* audio element */} -