Routing to page A or Page B based on API response - javascript

I am stuck on an issue. Let's say I have a home page. From this home page, I want to route to either page A or page B.
I have a list of items on the home page and what I need to do is when I click on any item in the list, it makes a GET API call, and based on one field in the response which is a boolean, I either need to redirect to page A or page B.
Basically, I need to call an API on the click of the item and get the response before it is routed to either Page A or Page B.
Many thanks in advance

if you're using Next.JS, use useRouter prop to achieve this.
for example
import {useRouter} from "next/router";
export default function Page() {
const router = useRouter()
async function route() {
let res = await apiFunctionCall();
if (res) {
await router.replace({
pathname: '/page1'
})
} else {
await router.replace({
pathname: 'page2'
})
}
}
}

The closest solution I could get is to create a Lazy loaded component which calls the API and then based on the response, routes to either page A or Page B.
Before routing to the correct page based on the data that has been returned, the data first needs to be stored in a variable. The data will be stored in the res variable. The if else statement will then route to either page A or B based on the data.
<code>const Response = res.data;
if(Response.type === 'A'){
this.props.history.push('/page-a');
} else {
this.props.history.push('/page-b');
}
</code>

Related

How to show error page without changing current URL

I have a custom 500 error page called 500.tsx and I want to able to show this page when request from client fails with status of 500, but keeping client on old url (for example /auth/register). I have a axios listener on error which should do all the work. But could not find a way to do this using next/router. Any help appreciated
Didn't realize OP wanted to show 500 page at first.
You could look into router.isFallback but I am not entirely sure if that's appropriate for this.
It's supposed to be for Page Loading Indicators, but in your case, since the page will never load, it could work.
https://nextjs.org/docs/basic-features/data-fetching#fallback-true
return router?.isFallback
? <Custom500Page/>
: <RegularPage/>
You can set this variable from getStaticPaths method, which runs during build time and is usually used for [slug] pages.
// This function gets called at build time
export async function getStaticPaths() {
// Fetch paths to your slug pages here
return {
// paths,
fallback: true
}
}
Showing 404 page is quite straight forward & This is how we do.
Rendering 404 page
You can conditionally export a variable called notFound as true from getStaticProps method.
If the URL is invalid and you don't data to render the page, you simply pass that notFound prop as true and then the default or custom 404 page will show up automatically preserving your invalid url.
// This function gets called at build time
export async function getStaticProps({ params, preview = false }) {
let pageData
try {
// fetch pageData from API here
} catch (error) {
// catch errors
}
// check validity or emptyness of data
// invalid URL (slug) -> empty data from API
// valid URL (slug) -> valid data from API
return isObjectEmpty(pageData)
? { notFound: true }
: {
props: {
pageData
// pass other props to the page
}
}
}
NextJS Docs on getStaticProps & not-found
https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation

getServerSideProps is not updating data with import

I'm having a problem with getServerSideProps in NextJS not updating values on page load. It seems to be having the same effect as using getStaticProps when calling from data that is an imported JSON file.
Here's the applicable code:
/update/[...id].js
import { hasPermission, getPermissions } from '../../lib/permissions'
...
//in the page function I use the ternary to check permission of the user
{ (hasPermission(session.user.email, `${params.id[0]}-edit`, permissions)) ? <HasPerm /> : <NoPerm /> }
...
export async function getServerSideProps(context) {
const params = context.query
const permissions = getPermissions()
return {
props: { params, permissions }
}
}
/lib/permissions.js
import permissions from '../db/users.json'
export function hasPermission(username, group, perm = false) {
if (!perm)
perm = permissions
if (username in perm && perm[username].groups.includes(group)) {
return true
}
if (perm.all.groups.includes(group)) {
return true
}
return false
}
export function getPermissions() {
return permissions
}
For SSR pages that were understandably doing this to begin with, I pass in the permissions to the page in getStaticProps and pass those values into my hasPermission() function in those pages so that they are revalidated on permissions change. Yet there is no revalidation option in getServerSideProps so the data is not revalidated at all. I was using getInitialProps before but pretty much everyone discourages that because it disables ASO.
How do I use getServerSideProps such that my imported json is at least revalidated?
I ended up not using the json import and used fs instead for other reasons but the issue is resolved by using dynamic imports in the getServerSideProps:
export async function getServerSideProps(context) {
const permissions = await import('../db/users.json')
}
Also don't make my same mistake of passing the whole permissions database to every user as was being done by using a function like getPermissions in getStaticProps to get the data to the hasPermission function in the page. Instead, only serve data with getServerSideProps if the user has permission. In other words, ensure you're holding the data back from the server-side. Then you can also pass through an individual's permissions to the page if you need to, like for displaying a message saying you don't have permission.

Nextjs: render page or show 404 page based on user data

We are currently working on a Nextjs project which includes a number of dynamic pages. We have come to a stage where we are defining the dynamic paths using getStaticProps and getStaticPaths. So far we managed to define 404 pages in dynamic pages with a similar structure to the below:
export async function getStaticProps(context) {
const { id } = context.params
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
const user = await response.json()
return {
props: { user },
notFound: Object.keys(user).length === 0
}
}
export function getStaticPaths() {
return {
paths: [],
fallback: 'blocking'
}
}
Using version 10's notFound value and fallback: blocking allows us to have the page return a 404 status code (for some reason fallback: true returns a 200 status code).
The issue we currently have is to display a 404 page to pages that depend on user data such as username or user locale. One way we thought we could solve this is by having those pages as Server Side generated rather than Static Site generated by using getServerSideProps:
export async function getServerSideProps(context) {
const userId = getCookie('user_id')
const response = await fetch(`___/checkUserAccess/${userId}`)
const access = await response.json()
return {
props: { ... },
notFound: !access.userAllowed
}
}
I suppose I am answering my own question here as going for Server Side for these pages to show 404 pages based on user data seems logical. However the concern is the impact it may have on the website as a whole. These pages could easily end up being hundreds of pages.
Should we be concerned about this? Or maybe there's another way to go about solving this?

How to get only one user instead of a list?

I try to get from a list of users to only one user and display his profile on another page.
I want to do so with the routerLink and passing on an id of this specific user to the next page.
The routing is working, Im directed to the profile page but when I log the results of the http request I still get back the whole list of users like in the users page instead of the details of one user.
I have tried many things like changing the path of the url in my user.service.ts but that didn't solve the problem I even got 404 request errors when using this path ${this.url}/users/${id}/ instead of ${this.url}/users/?i=${id}/ (where its working).
The api docs is saying though that in order to retrieve one single user its http://1234//users/{id}/ it this scheme while id is an integer. But when I want to apply that scheme I get the 404 error.
Thats why I have to use the ?I= version but there the problem is I only get the full list of users on the next page.
MY CODE:
user.service.ts
// get a user's profile
getUserDetails(id): Observable<any> {
return this.http.get(`${this.url}/users/?i=${id}/`); // why add ?i
}
user.page.ts
// get all users in the users page
getAllUsers() {
this.userList = this.userService.getList()
.pipe(map(response => response.results));
}
user.page.html
<ion-avatar class="user-image" slot="start" [routerLink]="['/','profile', 'user.id']">
<ion-img src="assets/22.jpeg"> </ion-img>
</ion-avatar>
profile.page.ts
information = null;
...
ngOnInit() {
// Get the ID that was passed with the URL
let id = this.activatedRoute.snapshot.paramMap.get('id');
// Get the information from the API
this.userService.getUserDetails(id).subscribe(result => {
this.information = result;
console.log(result);
});
}
It seems like the url is wrong. If it was me I would console.log the url and compare it to the docs. Heres a snippet to try a few variations:
const id = 1;
const options = [
`${this.url}/users/?i=${id}/`,
`${this.url}/users/?i=${id}`,
`${this.url}/users/i/${id}/`,
`${this.url}/users/i/${id}`,
`${this.url}/user/?i=${id}/`,
`${this.url}/user/?i=${id}`,
`${this.url}/user/i/${id}/`,
`${this.url}/user/i/${id}`,
];
for (const option of options) {
try {
const response = await this.http.get(option);
console.log(options, response);
} catch (e) {
}
}
I would also consider dropping the second http request. If the first request returns all the required data you could just store it in a variable on the service.

How to fetch data properly from route params?

I have one 'main' route with current data presented and another route with 'favorites'
when user click on a favorite component im sending him to the main route and need to present the new data fetched from an api and updating via redux.
So im using the code below in the main component , but what i get is that the previous data is presented for a few second and only then it changes :
async componentWillMount(){
let {cityName} = this.props.match.params
if (cityName) return await this.props.onDataLoad(cityName)
if (!dailyForecasts) await
this.props.onDataLoad(this.state.defaultCity)
}
How can i avoid this behavior ?

Categories