React Display PDF from authenticated backend - reactjs

I have a React Frontend and Django Backend. In my frontend I want to include a view for the PDF obtained by the backend. I tried using iframe and object HTML Tags, but they failed due to the missing authentication. My suggested approach would be requesting the PDF with axios.get, since this automatically handles the authentication. However, I could not find out how to handle the obtained PDF in case of temporarily storing and displaying it with react.
Currently my function is able to obtain the PDF and display it in a new window but I want to include it as an element within the current page.
const getPDF = () => {
axios
.get(
`${process.env.REACT_APP_API}/Link/to/the/PDF/`,
{
responseType: "blob",
}
)
.then((r) => {
window.open(URL.createObjectURL(r.data));
});
};

#react-pdf/renderer is used to render pdf from your page/application and is not made to render already made pdfs
You can use react-pdf to do what you want. It works great and lets you style your component the way you want.

In the content of the page I put the following:
<iframe src="" width={600} height={600} />
And I adapted the function to fill the iframe:
const getPDF = () => {
console.log("getPDF");
axios
.get(`${process.env.REACT_APP_API}/Link/to/the/PDF/`, {
responseType: "blob",
})
.then((r) => {
console.log(r.data);
const file = window.URL.createObjectURL(r.data
);
const iframe = document.querySelector("iframe");
if (iframe?.src) iframe.src = file;
})
.catch((err: AxiosError) => {
console.log(err);
});
};

So you have half the work done! in the other half, maybe an option is to look at this component:
#react-pdf/renderer
I used this package without any complaints.
** Sorry for redirecting to the wrong library. I use this instead:
pdf-viewer-reactjs

Related

I want to show only mapped URL instead of project URL mixing

I'm new to react. I have a problem with url.
I get data from Github API through fetch request. Now I have to show only URL from API data but it shows me project url and data url mixed.
Here's the code which will simplify the problem.
fetch(
`https://api.github.com/users/${username}/repos?per_page=${count}&sort=${sort}&client_id=${clientId}&client_secret=${clientSecret}`
)
.then((res) => res.json())
.then((data) => {
this.setState({ repos: data });
})
.catch((err) => console.log(err));
this will update state with result data.
Here I destructured it from state.
const { repos } = this.state;
<Link to={repo.html_url} className="text-info" target="_blank">
{repo.name}
</Link>
now I mapped repos and return JSX and show html_url from data. But the problem I'm facing is not showing url from data.
It shows like this
<a class="text-info" target="_blank" href="**/profile/**https://github.com/ahsandani001/amazon-clone">amazon-clone</a>
I copy this from chrome devtools. ("/profile/" is extra).
How can I remove this. Where am I mistaken?
Somebody help. Thanks in advance.

Fetch data using an id from an api but display an alternative text to address bar e.g. content_title in Next.js

I'm using an api that only allows fetching data using an id BUT NOT title as follows http://0.0.0.0:5000/blog/13b03a39-bc04-4604-baf6-059658f9f5e8 . The endpoint returns a JSON object which I want to render to browser using Next Js. However I want to have a clean url architecture that contains title as follows:
instead of a url containing the id as follows:
Here's how I'm passing props to Link :
<Link
href={`/post/${post.blog_title}`}
as={`/post/${post.blog_title}`}>
<a className='blog__card--link'>
<h4 className='blog__card--title'>{post.blog_title}</h4>
</a>
</Link>
and here's is my [id].js file:
import { getBlog } from '../../api/index';
const Article = ({ blog }) => {
const router = useRouter();
return (
<div class='article'>
<div class='article__main'>
{/* {console.log(router)} */}
<ArticleView />
</div>
</div>
);
};
Article.getInitialProps = async (router) => {
const res = await getBlog(`${router.query.id}`);
const json = await res.json();
console.log(json);
return { blog: json };
};
export default Article;
Trying to access ${router.query.id} in getInitialProps it returns the title which I understand is what I'm passing through as prop in Link.
Is it possible to achieve a clean url structure but also use id in getInitialProps? and how can I achieve it using dynamic links in Next.js ?
IMPORTANT UPDATE
-> The only good alternative is to use slugs in the API because imagine someone follows a link to your post from another site or perhaps enter the URL in the browser address bar? How would you know what to query for from the backend? Therefore this question comes from a place of impracticality , choosing to retain it on the site for the sake of others in the future.
you need to import Next/Router
import { useRouter } from 'next/router'
change your getInitialProps function to
Article.getInitialProps = async (router) => {
//get id query parameter
const res = await getBlog(`${router.query.id}`);
const json = await res.json();
console.log(json);
return { blog: json };
};
this should work for you
https://nextjs.org/docs/api-reference/data-fetching/getInitialProps#context-object
Article.getInitialProps = async function(context) => {
const res = await getBlog(`${context.query.id}`);
const json = await res.json();
console.log(json);
return { blog: json };
};
solution 1
however this base on your endpoint my suggest is change endpoint to receive slug so you can manage your slug
solution 2
not best practice but you can get clean url and get data by id Using Redux
solution 3
using next-routes using next-routes and pass id as params
<Link route='blog' params={{id: data.id}}>
<a>Hello world</a>
</Link>
What I was trying to achieve in this question is not practical therefore I settled to having unique slugs in the back-end that can be used to fetch the specific data.
Take a scenario where a link to your article/post is shared somewhere else, then the only way to get data to that post/article is using a slug.

Getting 404 when first loading dynamic routes on nextjs

I'm trying to create a blog page to test nextjs and created a dynamic route for the posts, which will be retrieved from Contentful. When navigating from Home page and clicking into a next/router <Link /> component, the blog post loads correctly, but if I get the URL and try loading the page directly from browser address bar, I'll get 404.
Steps to reproduce:
1. git clone https://github.com/zeit/next-learn-demo.git
2. cd next-learn-demo/8-deploying
3. yarn
4. next build && next export
5. cd out
6. serve
7. Navigate to http://localhost:5000/p/learn-nextjs
8. See 404
Is this a limitation of NextJS (didn't find anything related to it on documentation) or do we need to configure anything else?
The real issue is that exporting a next app will make it generate static HTML files. Even though it will still be able to request data before rendering the page, the set of available paths are not dynamic (they are generated during the next export command). See this docs and this example.
Based on this, I have 2 possible solutions:
generate a webhook to trigger a next build && next export command every time a new blog post is published in Contentful;
avoid exporting my next app and host a Node server that will handle the dynamic routes.
That's because when you directly access the link or refresh the page then it add's a slash at the end of route. An next.js doesn't recognize any route like that. To fix this, I hope there should be an easiest way to do that. However you can do this using custom server. Here is an example:
server.get("/about/", (req, res) => {
return app.render(req, res, "/about")
});
Hope this will help you.
To extend the answer provided by #Minoru, the official Next documentation covers this case in this example.
Using getStaticPaths and getStaticProps allows you to create dynamic pages at build time, avoiding the 404.
Example code for posts dynamic page:
import { GetStaticPaths, GetStaticProps } from 'next';
const Post = ({ post }) => {
const { id, content } = post;
return (
<div>
<h1>Post {id}</h1>
<p>{content}</p>
</div>
);
};
export const getStaticPaths: GetStaticPaths = async () => {
// Get all posts via API, file, etc.
const posts = [{ id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }, { id: '5' }]; // Example
const paths = posts.map(post => ({
params: { id: post.id },
}));
return { paths, fallback: false };
};
export const getStaticProps: GetStaticProps = async context => {
const postId = context.params?.id || '';
// Get post detail via API, file, etc.
const post = { id: postId, content: `I'm the post with id ${postId}!` }; // Example
return { props: { post } };
};
export default Post;
When building the site with next build && next export we will see in the out folder that Next has created each post page
Then, when you navigate to /posts/3/ you will see the post with id 3
For reference, this docs page contains this case and many other use cases.
Don't want to infringe any old posts rules, but in case anyone else in my context I use vercel's feature webhook to new deploys and as I was using firebase I've created a simple firebase function whith is hooked to a new event creation of a page triggers the webhook. I've used fetch because we can make a GET request according to the docs
exports.newEventAdded = functions.region('us-central1').firestore.document('local_events/{localeventId}')
.onCreate((snap, context) => {
fetch('https://api.vercel.com/v1/integrations/deploy/process.env.NEXT_PUBLIC_VERCEL_WEBHOOK_ID')
.then(function (response) {
return response.json();
})
.then(function (myJson) {
console.log(JSON.stringify(myJson));
});
})

prismic preview not displaying updated content in gatsby

I'm developing site with Gatsby and Prismic.
I am implementing prismic preview with prismic-javascript. When click the preview on prismic, gatsby redirecting it to the proper URL but updated content not displaying now.
I tried to use the gatsby-source-prismic-preview plugin but it not worked.
const Preview = ({ history, location }) => {
useEffect(() => {
const params = qs.parse(location.search.slice(1))
if (!params.token) {
return console.warn(`No token available, check your configuration`)
}
client.previewSession(params.token, linkResolver, '/')
.then(url => {
navigate(url);
})
.catch(err => console.log(err))
})
return null
}
This is my preview page.
Please let me what is my mistake.
I'm not familiar with gatsby-source-prismic-preview but I'm not sure it's really up to date anymore.
You should take a look at https://github.com/birkir/gatsby-source-prismic-graphql, It's the official plugin developed by the same guy that does gatsby-source-prismic-preview and it's backed up by the Prismic team.
Maybe open an issue on GitHub if you don't feel like migrating to the new one.

react-player and authorization required problem

I am developing an application where server streams some video files and ReactJS-based client can play that stream using react-player.
Everything works great when I'm playing the stream using ordinary url variable from ReactPlayer component. But now I need to pass some data (authorization token) in header along with request to get access to the stream.
Ideally would be to somehow make request to the stream using Fetch API and then bypass only video data to ReactPlayer component, but I'm not sure if it is possible.
Does react-player supports such situation? If not, how can I achieve this or is there any other universal video player I can use that supports custom request crafting?
If that matters backend server is a Flask based REST api application.
The solution I used is to modify the XHR request send by HLS when loading the stream.
This is made by giving to ReactPlayer component some options for hls :
<ReactPlayer
config={{
file: {
hlsOptions: {
forceHLS: true,
debug: false,
xhrSetup: function(xhr, url) {
if (needsAuth(url)) {
xhr.setRequestHeader('Authorization', getToken())
}
},
},
},
}}
/>
The list of options for hls is available here.
You may use this since react-player version 1.1.2 according to this github issue
I spent several hours on this until finally found this amazing answer. It worked for me since I needed to pass down the token on the authorization prop.
If your file server supported CORS, you could use fetch and URL.createObjectURL
const token = getUserToken();
const CustomVideo = ({ videoUrl }) => {
const options = {
headers: {
Authorization: `Bearer ${token}`
}
}
const [url, setUrl] = useState()
useEffect(() => {
fetch(videoUrl, options)
.then(response => response.blob())
.then(blob => {
setUrl(URL.createObjectURL(blob))
});
}, [videoUrl])
return (
<ReactPlayer url={url} width="100%" controls />
)
}
Check the details here : https://github.com/CookPete/react-player/issues/282

Resources