I'm having hard time understanding why my local routing and production routing are mismatching.
I'm writing an app in next.js
In my _app.tsx file I have following lines
if (!isUserLogged && Component.isRestricted) {
redirect(res, '/login');
return { pageProps: {} };
}
if (isUserLogged && !hasUserGivenConsent && !Component.tosPage) {
redirect(res, '/accept-tos');
return { pageProps: {} };
}
if (isUserLogged && hasUserGivenConsent && Component.tosPage) {
redirect(res, '/');
return { pageProps: {} };
}
if (isUserLogged && Component.isAuthPage) {
redirect(res, '/');
return { pageProps: {} };
}
Component.someProperty are always statics in pages/somePage.tsx files.
isUserLoggedIn and hasUserGivenConsent are redux toolkit state.
My pages/login.tsx:
class LoginPage extends Component {
static isRestricted = false;
static isAuthPage = true;
static getInitialProps = wrapper.getInitialPageProps(store => async ({
res,
query: {
token,
uid,
},
}) => {
const { dispatch }: { dispatch: AppThunkDispatch } = store;
if (
!!token && typeof token === 'string' &&
!!uid && typeof uid === 'string'
) {
await dispatch(activateUser({
token,
uid,
}))
.unwrap()
.catch(e => {
redirect(res, '/expired-link ');
});
} else {
dispatch(clearActivationStatus());
}
return {};
});
render() {
return (
<LoginForm />
);
}
}
Locally everything works as expected:
not logged user, trying to access restricted page -> /login
logged user, tos not accepted -> /accept-tos
logged user, tos accepted, trying to access tos page -> /
user clicking on activation mail is directed to /login?uid=...&token=... -> getInitialProps check if there are uid and token if so, then it posts a request to backend to activate account -> if ok user stays on login page -> if not redirects user to /expired-link
Production behavior:
(current problem) no matter if user is logged in or not it redirects to /accept-tos from any URL I type into browser.
(previous problem, not achievable due to current problem) If user clicked on the activation link /login?uid=...&token=... it redirected to / which is restricted path
Nevermind, I ran a gitlab job that cleared the environment so thus it wasn't working.
Related
In product page, I want to get all images path that are in a specific folder and send those to client side, so I can use them in client side by passing the paths to Image component of next js. I tried this when I was developing my app via running npm run dev and it was successful. Then I pushed the changes to my GitHub repository and vercel built my app again. Now, when I go to the product page, I get an error from the server. I tried some ways to fix this problem, but I couldn't fix that. For example, I tried changing my entered path in readdir, but the problem didn't fix. Here are my codes:
const getPagePhotosAndReview = async (productName) => {
const root = process.cwd();
let notFound = false;
const allDatas = await fs
.readdir(root + `/public/about-${productName}`, { encoding: "utf8" })
.then((files) => {
const allDatas = { pageImages: [], review: null };
files.forEach((value) => {
const image = value.split(".")[0];
const imageInfos = {
src: `/about-${productName}/${value}`,
alt: productName,
};
if (Number(image)) {
allDatas.pageImages.push(imageInfos);
}
});
return allDatas;
})
.catch((reason) => (notFound = true));
if (notFound) return 404;
await fs
.readFile(root + `/public/about-${productName}/review.txt`, {
encoding: "utf-8",
})
.then((value) => {
allDatas.review = value;
})
.catch((reason) => {
allDatas.review = null;
});
return allDatas;
};
export async function getServerSideProps(context) {
if (context.params.product.length > 3) {
return { notFound: true };
}
if (context.params.product.length < 3) {
const filters = {
kinds: originKinds[context.params.product[0]] || " ",
};
if (context.params.product[1]) filters.brands = context.params.product[1];
const products = getFilteredProducts(filters, true);
if (products.datas.length === 0) {
return {
notFound: true,
};
}
return {
props: {
products: { ...products },
},
};
}
if (context.params.product.length === 3) {
const filters = {
path: context.resolvedUrl,
};
const product = getFilteredProducts(filters, false);
if (product.length === 0) {
return {
notFound: true,
};
}
const splitedPath = product[0].path.split("/");
const pagePhotosAndReview = await getPagePhotosAndReview(
splitedPath[splitedPath.length - 1]
);
if (pagePhotosAndReview === 404) return { notFound: true };
product[0] = {
...product[0],
...pagePhotosAndReview,
};
product[0].addressArray = [
textOfPaths[context.params.product[0]],
textOfPaths[context.params.product[1]],
];
return {
props: {
product: product[0],
},
};
}
}
This is the base code and I tried some ways but couldn't fix the problem. So to fix this problem, I want to ask: how can I get the name of all images in a specific directory and then use those images in client side? And errors that I get: if I go to a page directly and without going to the home of the website, I get internal server error with code of 500 and when I go to a page of my website, and then I go to my product page, I get
Application error: a client-side exception has occurred (see the browser console for more information).
And I should say that I know I should remove public from paths when I want to load an image from public folder. I did it but I still get error.
I am using detectAdBlock library to detect ad-blocks.
Based on the response,I am calling a checkin API.
That API gives a boolean if user visits the page for the first time, it returns true.
When the response is true, I have created a profile popup modal which only appears when the Check-in API response is true.Currently I have a logic like if ad-blocker is enabled, I am not calling that API.When the user disables the ad-block, then only the API was getting called.
Now I have added a close button on my Ad-Block popup and because of that the user can turn off the ad-block popup but are not able to see the profile Popup because the check-In API doesn't get called because the ad-blocker library response is still true.
Here is the code -->
Main.js
componentDidMount() {
detectAnyAdblocker().then((detected) => {
if (!detected) {
this.props.checkInAPI(params).then((resp) => {
localStorage.setItem('firstTimeUserVisit', resp && resp.data === true);
const userId = localStorage.getItem('userId');
});
}
});
}
render() {
return (
<AdBlock />
)
}
Profile.js (Popup condition)
const firstTimeCheckIn = localStorage.getItem('firstTimeUserVisit');
if (firstTimeCheckIn === 'true' && !adBlock) {
setShowProfilePopup(true);
}
return (
{showProfilePopup && (<PopupModal> ..... </PopupModal>)}
)
AdBlock.js
let closeAdBlock = false;
const AdBlock = ({ eventData }) => {
const [adBlock, setAdBlock] = useState(false);
const onCloseAdBlock = () => {
setAdBlock(false);
closeAdBlock = true;
};
useEffect(() => {
if (!closeAdBlock) {
detectAnyAdblocker().then((detected) => {
if (detected) {
setAdBlock(true);
}
});
}
}, [adBlock]);
return (
<PopupModal
id="adblock-popup"
custClassName={'adblock-popups'}
onCloseFunc={() => onCloseAdBlock()}
showModal={adBlock}
>.....</PopupModal>
)
I want the API should be called whether a user has ad-block enabled or disabled but the profile popup should also be shown if user visits the page for the first time
Hello I have an application in react and it is working perfectly. All routes, page loads. Everything perfect. However, when entering the FarmProperty page and trying to reload it (F5) the error TypeError: Cannot read property 'tenant_account' of undefined occurs.
FarmProperty.js
import { connect } from 'react-redux';
import * as actions from '../../store/actions/farmProperty';
class FarmProperty extends Component {
state = {
page: 0,
limit: 15,
msg: "",
erro: "",
success: "",
loading: false,
openModal: false,
id_delete: "",
tenant_account_id_delete: "",
apiData: false
}
componentDidMount() {
this.getFarmProperties();
}
componentDidUpdate(nextProps) {
if (!this.props.user && nextProps.user) this.getFarmProperties();
this.receiveApiData();
}
getFarmProperties() {
const { page, limit } = this.state;
const { farm_properties, user } = this.props;
//console.log(user);
this.props.getFarmProperties(user.tenant_account.id, page, limit);
if (this.props.location.state) {
this.setState({ msg: this.props.location.state.msg });
this.props.location.state.msg = "";
}
if (farm_properties === "undefined") return null;
}
receiveApiData() {
if (typeof this.props.farm_properties !== "undefined" && this.props.farm_properties !== null
&& !this.state.apiData && this.props.farm_properties.data.currentPageNumber === this.state.page) {
this.setState({ apiData: true });
}
}
render() {
return (
<>
</>
)
}
}
const mapStateToProps = state => ({
farm_properties: state.farmProperty.farm_properties,
user: state.auth.user
})
export default connect(mapStateToProps, actions)(FarmProperty);
I believe the problem lies in the function
this.props.getFarmProperties (user.tenant_account.id, page, limit);
when I'm passing the user.tenant_account.id parameter. This parameter is the user who is logged in to the application and I need to get this information, but if there is any other way to get this information, I would be grateful for the help.
I am using the bot framework-webchat 0.12.0 version for a React App. I am initializing the Chat component with custom botconnection, creating a backchannel mechanism.
Does anyone know how to unsubscribe / destroy all bot activities in the backchannel?
When I inspect the network tab it seems that when I navigate with the react router to the view which contains the webchat component, a WebSocket connection is initialized every time and it stays open even after the component has been unmounted (navigate away).
I am afraid those web socket connections might become a problem if they don't get removed.
Here is what I am doing in my React component:
import { Chat, DirectLine } from 'botframework-webchat';
...
componentDidMount() {
const { user, token } = this.props;
if (token && user && Object.keys(user).length !== 0) {
this.botConnection = new DirectLine({
secret: configs.bot.secret_key,
webSocket: 'true'
});
this.initBot();
}
}
initBot = () => {
const { token, user } = this.props;
this.botConnection.postActivity({
type: 'event',
value: {
accessToken: token,
context: 'user'
},
from: {
id: user.userName
},
name: 'conversationInfo'
}).subscribe(() => {
this.setState({ renderChatBot: true });
});
}
...
render() {
const { token, user } = this.props;
if (token !== '' && this.state.renderChatBot) {
console.log('BOTCHAT RENDER');
return (
<Chat
bot={{ id: configs.botId }}
botConnection={this.botConnection}
user={{ id: user.userName }}
token={token}
resize="detect"
/>
);
}
return null;
}
I have spent a few hours searching trough the documentations and also reading trough the files and I can not seem to find a way to destroy those web socket connections when the webchat component get's unmounted.
Any help would be greatly appreciated.
I'd like to understand how to make Hello.js work with React.js , especially the custom event handler hello.on
As I'm new to React.js, I don't understand how to bind non React events into the app flow.
I tried putting the event handler in the componentDidMount handler
handleClick(){
hello('twitter').login();
}
componentDidMount(){
hello.on('auth.login', function(auth) {
// Call user information, for the given network
hello(auth.network).api('/me').then(function(r) {
console.log(r);
});
});
hello.init({
'twitter' : 'J1jqqO50tcLtLx8Js0VDitjZW'
},
{
redirect_uri:'/',
oauth_proxy: 'https://auth-server.herokuapp.com/proxy'
});
}
thanks
And 3 years later:
You need a class for authentication, for example:
import * as React from "react";
import * as hello from "hellojs";
import { Event } from "../interfaces/Event";
export class Authentication extends React.Component<{}, { sendEvent: boolean }> {
constructor(public props, public context) {
super(props, context);
this.state = {
sendEvent: true
};
}
public login(network) {
hello.init({
aad: {
name: "Azure Active Directory",
oauth: {
version: 2,
auth: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
grant: "https://login.microsoftonline.com/common/oauth2/v2.0/token"
},
// Authorization scopes
scope: {
// you can add as many scopes to the mapping as you want here
profile: "user.read",
offline_access: ""
},
scope_delim: " ",
login: p => {
if (p.qs.response_type === "code") {
// Let's set this to an offline access to return a refresh_token
p.qs.access_type = "offline_access";
}
},
base: "https://www.graph.microsoft.com/v1.0/",
get: {
me: "me"
},
xhr: p => {
if (p.method === "post" || p.method === "put") {
JSON.parse(p);
} else if (p.method === "patch") {
hello.utils.extend(p.query, p.data);
p.data = null;
}
return true;
},
// Don't even try submitting via form.
// This means no POST operations in <=IE9
form: false
}
});
hello.init(
{
aad: "ClientID"
},
{
redirect_uri: "YOUR REDIRECT_URI",
//redirect_uri: 'https://localhost:4321/temp/workbench.html',
scope: "user.read"
}
);
// By defining response type to code, the OAuth flow that will return a refresh token to be used to refresh the access token
// However this will require the oauth_proxy server
hello(network)
.login({ display: "none" })
.then(
authInfo => {
console.log(authInfo);
localStorage.setItem("logged", authInfo.authResponse.access_token);
},
e => {
console.error("Signin error: " + e.error.message);
}
);
}
//when the component is mounted you check the localstorage
//logged ==> undefined you call login and save a token in localstorage
//logged ==> with a token -> setEvent call a function that use graph api
public componentDidMount() {
let logged = localStorage["logged"];
if (logged === undefined) this.login("aad");
else {
if (this.state.sendEvent) {
this.props.setEvent(null);
this.props.setEvent(Event.GET_ALL_USERS);
}
}
}
public render() {
return null;
}
}
the file name is auth.tsx and you can call this class in the main react class:
export class mainClass extends React.Component{
......
......
private getEvent = (event) => {
this.setState({ event: event });
//HERE YOU recive the event when auth is ready
}
public render(){
<Authentication setEvent={this.getEvent} />
}
}