Iframe preview "Invalid time value" error for documents without publishedAt date

1 replies
Last updated: Jun 14, 2021
Hey guys just wondering if anyone can give me a firm nudge in the correct direction
I’m building a directory site for a client built on top of the official Gatsby/Sanity Blog starter. I’m wanting to implement iframe preview for both the blog posts and for directory entries. I modified the code from the starter’s IframePreview.js file to include some conditional logic that’s supposed to allow both documents to render previews. Here’s my code:


/* eslint-disable react/no-multi-comp, react/no-did-mount-set-state */

import React from "react";

import PropTypes from "prop-types";

import { format } from "date-fns";

import styles from "./IframePreview.module.css";


/**

* Explore more examples of previews:

* <https://www.sanity.io/blog/evolve-authoring-experiences-with-views-and-split-panes>

*/


const assemblePostUrl = ({ _displayed_, _options_ }) => {

const { slug, publishedAt } = _displayed_;

const { previewURL } = _options_;

if (!slug || !previewURL) {

console.warn("Missing slug or previewURL", { slug, previewURL });

return "";

}

const dateSegment = format(new Date(publishedAt), "yyyy/MM");
`const path = `/${dateSegment}/${slug.current}/`;`
`return `${previewURL}/blog${path}`;`

};


const assembleCompanyUrl = ({ _displayed_, _options_ }) => {

const { slug } = _displayed_;

const { previewURL } = _options_;

if (!slug || !previewURL) {

console.warn("Missing slug or previewURL", { slug, previewURL });

return "";

}
`const path = `/${slug.current}/`;`
`return `${previewURL}/companies${path}`;`

};


const IframePreview = (_props_) => {

const { options } = _props_;

const { displayed } = _props_.document;


if (!displayed) {

return (

<div _className_={styles.componentWrapper}>

<p>There is no document to preview</p>

</div>

);

}


const blogUrl = assemblePostUrl({ displayed, options });

const companyUrl = assembleCompanyUrl({ displayed, options });


if (!blogUrl && !companyUrl) {

return (

<div _className_={styles.componentWrapper}>

<p>Hmm. Having problems constructing the web front-end URL.</p>

</div>

);

}


if (displayed._type == "post") {

return (

<div _className_={styles.componentWrapper}>

<div _className_={styles.iframeContainer}>

<iframe _src_={blogUrl} _frameBorder_={"0"} />

</div>

</div>

);

}


if (displayed._type == "company") {

return (

<div _className_={styles.componentWrapper}>

<div _className_={styles.iframeContainer}>

<iframe _src_={companyUrl} _frameBorder_={"0"} />

</div>

</div>

);

}

};


IframePreview.propTypes = {

document: PropTypes.object, _// eslint-disable-line react/forbid-prop-types_

options: PropTypes.object, _// eslint-disable-line react/forbid-prop-types_

};


IframePreview.defaultProps = {

document: null,

};


export default IframePreview;

However when I run everything, the blog previews work great, but when I click Web Preview on the directory entries I get an error that says “Invalid time value”. The directory entry slug path has no date value in it like the blog slug, and it’s reflected in my code above. Here’s the repo if it helps:
https://github.com/originellnav/modern-teams
AI Update

I can see the issue in your code! The problem is that both assemblePostUrl and assembleCompanyUrl are being called regardless of the document type, and assemblePostUrl is trying to format a date that doesn't exist on your company documents.

Looking at your code:

const blogUrl = assemblePostUrl({ displayed, options });
const companyUrl = assembleCompanyUrl({ displayed, options });

When you're viewing a company document, assemblePostUrl still runs and tries to execute this line:

const dateSegment = format(new Date(publishedAt), "yyyy/MM");

Since company documents don't have a publishedAt field, this throws the "Invalid time value" error.

The fix: Only call the appropriate URL assembly function based on the document type. Here's the corrected code:

const IframePreview = (props) => {
  const { options } = props;
  const { displayed } = props.document;

  if (!displayed) {
    return (
      <div className={styles.componentWrapper}>
        <p>There is no document to preview</p>
      </div>
    );
  }

  // Only assemble the URL for the appropriate document type
  let previewUrl;
  
  if (displayed._type === "post") {
    previewUrl = assemblePostUrl({ displayed, options });
  } else if (displayed._type === "company") {
    previewUrl = assembleCompanyUrl({ displayed, options });
  }

  if (!previewUrl) {
    return (
      <div className={styles.componentWrapper}>
        <p>Hmm. Having problems constructing the web front-end URL.</p>
      </div>
    );
  }

  return (
    <div className={styles.componentWrapper}>
      <div className={styles.iframeContainer}>
        <iframe src={previewUrl} frameBorder={"0"} />
      </div>
    </div>
  );
};

This way, you're only calling the URL assembly function that matches your document type, avoiding the date formatting error for company documents. The iframe rendering logic is also simplified since both document types can use the same iframe element.

Show original thread
1 reply
I think it was a scope issue, I got it working with this (for future reference):

const IframePreview = (_props_) => {

const { options } = _props_;

const { displayed } = _props_.document;


if (!displayed) {

return (

<div _className_={styles.componentWrapper}>

<p>There is no document to preview</p>

</div>

);

}


if (displayed._type == "post") {

const url = assemblePostUrl({ displayed, options });


if (!url) {

return (

<div _className_={styles.componentWrapper}>

<p>Hmm. Having problems constructing the web front-end URL.</p>

</div>

);

}


return (

<div _className_={styles.componentWrapper}>

<div _className_={styles.iframeContainer}>

<iframe _src_={url} _frameBorder_={"0"} />

</div>

</div>

);

} else if (displayed._type == "company") {

const url = assembleCompanyUrl({ displayed, options });


if (!url) {

return (

<div _className_={styles.componentWrapper}>

<p>Hmm. Having problems constructing the web front-end URL.</p>

</div>

);

}


return (

<div _className_={styles.componentWrapper}>

<div _className_={styles.iframeContainer}>

<iframe _src_={url} _frameBorder_={"0"} />

</div>

</div>

);

}

};

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?