Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[gh14] jump links #54

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions nextjs/src/lib/config.js
Original file line number Diff line number Diff line change
@@ -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',
};
28 changes: 28 additions & 0 deletions nextjs/src/lib/sanity.js
Original file line number Diff line number Diff line change
@@ -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);
32 changes: 32 additions & 0 deletions nextjs/src/lib/sanity.server.js
Original file line number Diff line number Diff line change
@@ -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());
}
29 changes: 27 additions & 2 deletions nextjs/src/modules/episodes/IndividualEpisodePage.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -34,12 +35,33 @@ const IndividualEpisodePage = ({
}) => {
// state
const [skipTo, setSkipTo] = useState(null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going to list out what I have changed.

This should be 0 not 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 (
<StyledIndividualEpisodePage>
<EpisodeSummary
Expand All @@ -56,6 +78,7 @@ const IndividualEpisodePage = ({
audioPath={audioPath}
episodeNumber={episodeNumber}
skipTo={skipTo}
play={play}
/>
</div>
<VerticalDivider />
Expand All @@ -67,7 +90,9 @@ const IndividualEpisodePage = ({

<div className="time-links">
{/* TIME JUMP LINKS */}
{timeJump && <JumpLinks className="jump-links time" timeJump={timeJump} handleClick={skipToTimestamp} />}
{timeJump && (
<JumpLinks className="jump-links time" timeJump={timeJump} skipToTimestamp={skipToJumpLinkTimestamp} />
)}

{/* SHOW LINKS */}
{listLink && <Links listLink={listLink} className="links" />}
Expand Down
8 changes: 4 additions & 4 deletions nextjs/src/modules/episodes/components/JumpLinks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -22,7 +22,7 @@ const JumpLinks = ({ className, timeJump, handleClick }) => {
{timeJump &&
timeJump.map((one) => (
<li key={one._key}>
<button type="button" onClick={(e) => onClick(e, one.time)}>
<button type="button" onClick={(e) => handleClick(e, one.time)}>
<div className="time-code">{calculateTime(one.time)}</div>
<div className="description">{one.description}</div>
</button>
Expand Down
12 changes: 7 additions & 5 deletions nextjs/src/modules/home/components/FeaturedEpisode.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
),
}),
};

Expand Down
31 changes: 22 additions & 9 deletions nextjs/src/modules/shared/components/AudioPlayer/WaveformPlayer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
import { useRef } from 'react';
import { useEffect, useRef } from 'react';
import styled from 'styled-components';

// styles
Expand All @@ -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
Expand All @@ -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 (
<StyledFeaturedAudioPlayer>
{/* audio element */}
<audio ref={audioPlayer} src={audioPath} preload="metadata" onLoadedMetadata={onLoadedMetadata} />
<audio ref={audioPlayer} src={audioPath} preload="metadata" />

{/* album cover */}
<div className="album-cover">
Expand Down Expand Up @@ -112,14 +123,16 @@ WaveformPlayer.propTypes = {
audioPath: PropTypes.string,
episodeNumber: PropTypes.number,
episodeTitle: PropTypes.string,
// skipTo: PropTypes.number,
skipTo: PropTypes.number,
play: PropTypes.bool,
};

WaveformPlayer.defaultProps = {
audioPath: '',
episodeNumber: '',
episodeTitle: '',
// skipTo: 0,
skipTo: 0,
play: false,
};

/** -------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useRef } from 'react';
import { useState, useRef, useEffect } from 'react';

export const useAudioPlayer = (audioRef, progressBarRef) => {
const [speed, setSpeed] = useState(1);
Expand All @@ -9,10 +9,16 @@ export const useAudioPlayer = (audioRef, progressBarRef) => {

const onLoadedMetadata = () => {
const seconds = Math.floor(audioRef.current.duration);
setDuration(seconds);
progressBarRef.current.max = seconds;
if (!Number.isNaN(seconds)) {
setDuration(seconds);
progressBarRef.current.max = seconds;
}
};

useEffect(() => {
onLoadedMetadata();
}, [audioRef?.current?.loadedmetadata, audioRef?.current?.readyState]);
Copy link
Contributor

@destinio destinio Aug 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

audioRef appears to be a required prop so it will always be there no need for the first ?

audioRed.current?.load.......

The ? only needs to be on properties that we have no clue if they are there or not.

I actually just learned this from James' optional chaining video


// when the playhead is moved, update the current time (text)
const updateCurrentTime = () => {
setCurrentTime(progressBarRef.current.value);
Expand Down Expand Up @@ -112,9 +118,11 @@ export const useAudioPlayer = (audioRef, progressBarRef) => {
timeTravel(Number(progressBarRef.current.value) + 30);
};

const skipToTime = (newTime) => {
const skipToTime = (newTime, autoPlay) => {
timeTravel(newTime);
play();
if (autoPlay) {
play();
}
};

// toggle play / pause when you tap the space bar
Expand Down
2 changes: 1 addition & 1 deletion nextjs/src/queries/Queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const RecentEpisodesQuery = groq`*[_type == "episode" && published == tru
publishedAt,
briefDescription,
audioPath
}[0...4]`;
}[0...5]`;

export const sponsorQuery = groq`*[_type == "sponsor" && associatedEmails match $email && published==true]{
title,
Expand Down
4 changes: 4 additions & 0 deletions nextjs/src/utils/timeHelpers.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
function calculateTime(secs) {
console.log('🚀 ~ file: timeHelpers.js ~ line 2 ~ calculateTime ~ secs', secs);

const minutes = Math.floor(secs / 60);
const returnedMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
const seconds = Math.floor(secs % 60);
const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
console.log('🚀 ~ file: timeHelpers.js ~ line 6 ~ calculateTime ~ seconds', returnedSeconds);
console.log('🚀 ~ file: timeHelpers.js ~ line 6 ~ calculateTime ~ minutes', returnedMinutes);
return `${returnedMinutes}:${returnedSeconds}`;
}

Expand Down
Loading