I am setting up a login page using google OAuth in react, I am following a youtube tutorial, everything seems to work fine but somehow after logging in, I am not being redirected to my homepage. here is the code (Login.jsx):
import React from 'react'
import GoogleLogin from 'react-google-login';
import { useNavigate } from 'react-router-dom';
import { FcGoogle } from 'react-icons/fc';
import carVideo from '../assets/car.mp4';
import logo from '../assets/speedograph white.png';
import { client } from '../client';
const Login = () => {
const navigate = useNavigate();
const responseGoogle = (response) => {
localStorage.setItem('user', JSON.stringify(response.profileObj));
if (response.profileObj) {
const { name, googleId, imageUrl } = response.profileObj;
const doc = {
_id: googleId,
_type: 'user',
userName: name,
image: imageUrl,
};
client.createIfNotExists(doc).then(() => {
navigate('/', { replace: true });
});
}
};
return (
<div className = "flex justify-start items-center flex-col h-screen">
<div className='relative w-full h-full'>
<video
src={carVideo}
type='video/mp4'
loop
controls={false}
muted
autoPlay
className='w-full h-full object-cover'
/>
<div className = "absolute flex flex-col justify-center items-center top-0 right-0 left-0 bottom-0 bg-blackOverlay">
<div className="p-5 ml-3">
<img src={logo} width="130px" alt="logo" />
</div>
<div className='shadow-2xl'>
<GoogleLogin
clientId={process.env.REACT_APP_GOOGLE_API_TOKEN}
render={(renderProps) => (
<button
type='button'
className='bg-white flex justify-center items-center p-3 rounded-lg cursor-pointer outline-none'
onClick={renderProps.onClick}
disabled={renderProps.disabled}
>
<FcGoogle className='mr-4' />Sign in with Google
</button>
)}
onSuccess={responseGoogle}
onFailure={responseGoogle}
cookiePolicy="single_host_origin"
/>
</div>
</div>
</div>
</div>
)
}
export default Login
I think the problem is due to the if condition, but I added it after reviewing a Stackoverflow tab that suggested adding it as a null check, before adding it I was getting the error:
Cannot destructure property 'name' of 'response.profileObj'
now the error is gone but it is not redirecting me to the home page (neither did it do so before the error). So where am I missing in my code exactly?
Related
For some reason when I click on one of the posts in the collection of posts section to view the info on one single post, my code is not adding a forward slash / in the URL like so : http://localhost:3000/postyou-just-could-not-have where the URL I need is http://localhost:3000/post/you-just-could-not-have.
Is there a way to add a / to the URL or figure out why it is not being generated?
App.js with Route <Route path="/post/:slug" element={<SinglePost />} /> in question :
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';
import SinglePost from './components/SinglePost';
import Post from './components/Post';
import Project from './components/Project';
import NavBar from './components/NavBar';
function App() {
return (
<Router>
<NavBar />
<Routes>
<Route path="/" element={<Home />} exact />
<Route path="/about" element={<About />} />
<Route path="/post/:slug" element={<SinglePost />} />
<Route path="/post" element={<Post />} />
<Route path="/project" element={<Project />} />
</Routes>
</Router>
);
}
export default App;
SinglePost.js component attempting to build URL from slug value :
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import sanityClient from '../client';
import BlockContent from '#sanity/block-content-to-react';
import imageUrlBuilder from '#sanity/image-url';
const builder = imageUrlBuilder(sanityClient);
function urlFor(source) {
return builder.image(source);
}
export default function SinglePage() {
const [singlePost, setSinglePost] = useState(null);
const { slug } = useParams();
useEffect(() => {
sanityClient
.fetch(
`*[slug.current == "${slug}"]{
title,
_id,
slug,
mainImage{
asset->{
_id,
url
}
},
body,
"name": author->name,
"authorImage": author->image
}`
)
.then((data) => setSinglePost(data[0]))
.catch(console.error);
}, [slug]);
if (!singlePost) {
return <div>Loading...</div>;
}
return (
<main className="bg-gray-200 min-h-screen p-12">
<article className="container shadow-lg mx-auto bg-green-100 rounded-lg">
<header className="relative">
<div className="absolute h-full w-full flex items-center justify-center p-8">
<div className="bg-white bg-opacity-75 rounded p-12">
<h1 className="cursive text-3xl lg:text-6xl mb-4">
{singlePost.title}
</h1>
<div className="flex justify-center text-gray-800">
<img
src={urlFor(singlePost.authorImage).url()}
alt="bob"
className="w-10 h-10 rouded-full"
/>
<p className="cursive flex items-center pl-2 text-2xl">
{singlePost.name}
</p>
</div>
</div>
</div>
<img
src={singlePost.mainImage.asset.url}
alt="gary"
className="w-full object-cover rounded-t"
style={{ height: '400px' }}
/>
</header>
<div className="px-16 lg:px-48 py-12 lg:py-20 prose lg:prose-xl max-w-full">
<BlockContent
blocks={singlePost.body}
projectId="notReally"
dataset="production"
/>
</div>
</article>
</main>
);
}
Adding Post.js :
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import sanityClient from '../client';
export default function Post() {
const [postData, setPost] = useState(null);
useEffect(() => {
sanityClient
.fetch(
`*[_type == "post"]{
title,
slug,
mainImage{
asset->{
_id,
url
},
alt
}
}`
)
.then((data) => setPost(data))
.catch(console.error);
}, []);
//anything wrapped in Link makes it clickable
return (
<main className="bg-green-100 min-h-screen p-12">
<section className="container mx-auto">
<h1 className="text-5xl flex justify-center cursive">Blog Post Page</h1>
<h2 className="text-lg text=gray-600 flex justify-center mb-12">
Welcome Doggies
</h2>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
{postData &&
postData.map((post, index) => (
<article>
<Link to={'/post' + post.slug.current} key={post.slug.current}>
<span
className="block h-64 relative rounded shadow leading-snug bg-white border-l-8 border-green-400"
key={index}
>
<img
src={post.mainImage.asset.url}
alt="photo"
className="w-full h-full rounded-r object-cover absolute"
/>
<span className="block relative h-full flex justify-end items-end pr-4 pb-4">
<h3 className="text-gray-800 text-lg font-blog px-3 py-4 bg-red-700 text-red-100 bg-opacity-75 rounded">
{post.title}
</h3>
</span>
</span>
</Link>
</article>
))}
</div>
</section>
</main>
);
}
Links are relative to the route hierarchy by default, unless given a value begin with /.
More about Link
In <Post />, try one of the following:
<Link to={post.slug.current} key={post.slug.current}>
...
/Link>
Or:
<Link to={'/post/' + post.slug.current} key={post.slug.current}>
...
/Link>
These will hopefully generate the right path as /post/:slug.
I have a list of data from graphql I am returning in from a service folder and referencing it in an index file, but for some unknown reason these data are not being fetched as I keep getting the error Cannot read properties of undefined (reading 'url') when I try to fetch a featured image and even after I comment the image line out, I get an empty result. I haven't spotted any error so please help me figure out what I may be doing wrong with the following code below
services/index.js
export const getBlogPosts = async () => {
const query = gql `
query MyQuery {
blogPostsConnection {
edges {
node {
title
slug
excerpt
createdAt
featuredImage {
url
}
blogcategories {
name
slug
}
blogTags {
name
slug
}
}
}
}
}
`
const results = await request(graphqlAPI, query)
return results.blogPostsConnection.edges
}
pages/blog.jsx
import React, {useState, useEffect} from 'react'
import {getBlogPosts} from '../services'
import {GiTimeBomb} from 'react-icons/gi'
import moment from 'moment'
const Home = () => {
const [blogposts, setBlogPosts] = useState([]);
useEffect(() => {
getBlogPosts().then((result) => {
setBlogPosts(result);
});
}, []);
return (
<div>
{blogposts.map((blogpost) => (
<div className="bg-white shadow-sm rounded-sm" key={blogpost.slug} blogpost={blogpost.node}>
<a href="#" className="overflow-hidden block">
<img src={blogpost.featuredImage.url} alt='no'className="w-full h-96 object-cover transform hover:scale-110 transition duration-500" />
</a>
<div className="p-4">
<a href="#">
<h2 className="text-2xl font-semibold text-gray-700 hover:text-blue-500 transition">{blogpost.title}</h2>
</a>
<p className="text-gray-500 text-sm mt-2">{blogpost.excerpt}</p>
<div className="flex mt-3 space-x-5">
<div className="flex items-center text-gray-400 text-sm">
<span className="mr-2 text-sx">
<i><AiOutlineUser /></i>
</span>
Kimmoramicky
</div>
<div className="flex items-center text-gray-400 text-sm">
<i className='pr-1 text-xs'><GiTimeBomb /></i>
<span>{moment(blogpost.createdAt).format('MMM DD, YYYY')}</span>
</div>
</div>
<div className='mt-4'>
Read more...
</div>
</div>
</div>
))}
</div>
)
}
export default Home
I am having an issue when trying to redirect to a different page after signing in with Google with my React 18 project. After logging in with google no redirects happen and I have no clue why not. Here is my Login.jsx file.
After clicking the Google Login button on my react page and successfully logging in with Google nothing changes.
import React from 'react';
import { GoogleLogin } from 'react-google-login';
import { GoogleLogout } from 'react-google-login';
import { createRoot } from 'react-dom/client';
import { useNavigate } from 'react-router-dom';
import { FcGoogle } from 'react-icons/fc';
import shareVideo from '../assets/share.mp4';
import logo from '../assets/logowhite.png';
import { client } from '../client';
const Login = () => {
const navigate = useNavigate();
const responseGoogle= (response) => {
localStorage.setItem('user', JSON.stringify(response.profile.Obj));
const { name, googleId, imageUrl } = response.profileObj;
const doc = {
_id: googleId,
_type: 'user',
userName: name,
image: imageUrl,
}
client.createIfNotExists(doc)
.then(() => {
navigate('/', { replace: true })
})
}
return (
<div className='flex justify-start items-center flex-col h-screen'>
<div className='relative w-full h-full'>
<video
src={shareVideo}
type='video/mp4'
loop
controls={false}
muted
autoPlay
className='w-full h-full object-cover'
/>
<div className='absolute flex flex-col justify-center items-center top-0 right-0 left-0 bottom-0 bg-blackOverlay'>
<div className='p-5'>
<img src={logo} width='130px' alt='Ack! This WAS a logo :/' />
</div>
<div className='shadow-2xl'>
<GoogleLogin
clientId="380323139927-1809a59ll0fp29rfo40jmubp01c2ife8.apps.googleusercontent.com"
render={(renderProps) => (
<button
type='button'
className='bg-mainColor flex justify-center items-center p-3 rounded-lg cursor-pointer outline-none'
onClick={renderProps.onClick}
disabled={renderProps.disabled}
onSuccess={responseGoogle}
onFailure={responseGoogle}
cookiepolicy='single-host-origin'
>
<FcGoogle className='mr-4' /> Sign in with Google
</button>
)}
/>
</div>
</div>
</div>
</div>
)
}
export default Login
Here is my index.js file if needed:
import React, { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter as Router } from 'react-router-dom';
import App from './App';
import './index.css'
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<Router>
<App />
</Router>,
document.getElementById('root')
);
If anyone knows anyway to sort this out I would appreciate it hugely. Thanks in advance.
localStorage.setItem('user', JSON.stringify(response.profile.Obj));
shouldn't it be:
localStorage.setItem('user', JSON.stringify(response.profileObj));
there is no "." between profile and Obj
Im working on a custom toast notification. But the hard part to me is I've not been able to hide the toast notification correctly. When I make a click to show it the toast has an animation to the left the problem is when the toast is gonna hide just disapear and it does not slide to the right. Im working with react and tailwind css. Here is the code. also leave a link to the case. https://codesandbox.io/s/toast-notification-ucx2v?file=/src/components/toastNotification.jsx
I hope you can help me guys.
-----App component-----
import { useEffect, useState } from "react";
import ToastNotification from "./components/toastNotification";
import "./styles.css";
export default function App() {
const [showToast, setShowToast] = useState(false);
const addToCart = () => {
setShowToast(true);
};
useEffect(() => {
setTimeout(() => {
setShowToast(false);
}, 3000);
}, [showToast]);
return (
<div className="App">
<ToastNotification showNotification={showToast} />
<button
className="w-1/2 p-2 flex items-center justify-center rounded-md bg-indigo-400 text-white"
type="submit"
onClick={addToCart}
>
Add to cart
</button>
</div>
);
}
-----Toast component-----
import React, { useEffect, useState } from "react";
const ToastNotification = ({ showNotification }) => {
useEffect(() => {
setTimeout(() => {}, 5000);
}, []);
return (
<>
{showNotification === false ? null : (
<div className="static z-20">
<div
className={`${
showNotification
? "animate__animated animate__slideInRight absolute top-16 right-4 flex items-center text-white max-w-sm w-full bg-green-400 shadow-md rounded-lg overflow-hidden mx-auto"
: "animate__animated animate__slideOutRight absolute top-16 right-4 flex items-center text-white max-w-sm w-full bg-green-400 shadow-md rounded-lg mx-auto"
}`}
>
<div class="w-10 border-r px-2">
<i class="far fa-check-circle"></i>
</div>
<div class="flex items-center px-2 py-3">
<div class="mx-3">
<p>add to car</p>
</div>
</div>
</div>
</div>
)}
</>
);
};
export default ToastNotification;
I'm using react with sanity io to create a portfolio page. I would like to create an unordered list according to how many tags I have a on a project. A project is composed of a title, image, description, and tags(this is just an array).
What I have tried is:
{project.tags.map(type => {
return (
<li>{type.type.name}</li>
)
})}
And I keep getting the error: "TypeError: project.forEach is not a function". If I just render
{project.tags}
all of the tags are displayed but then I can't style them hence the need to put them into a list.
Does anyone know how to accomplish this?
import React, { useEffect, useState} from "react";
import sanityClient from "../client.js";
import '../index.css';
export default function Project() {
const [projectData, setProjectData] = useState(null);
useEffect(() => {
sanityClient.fetch(`*[_type == "project"] | order(index) {
title,
mainImage{
asset->{
_id,
url
},
},
description,
projectType,
link,
tags
}`).then((data) => setProjectData(data)).catch(console.error);
}, []);
return (
<div className="antialiased text-gray-800 bg-gray-400">
<div className="container relative flex flex-col px-6 mx-auto space-y-8">
<div className="absolute inset-0 z-0 w-2 h-full bg-white shadow-md left-38 md:mx-auto md:right-0 md:left-0"></div>
{projectData && projectData.map((project, index)=> (
<div className="relative z-10 p-10 ">
<img src={project.mainImage.asset.url} alt={project.mainImage.alt} className="timeline-img" />
<div className={`${index % 2 === 0 ? "timeline-container-left timeline-container" : "timeline-container" }`} >
<p className="font-bold uppercase">{project.title}</p>
<div className={`${index % 2 === 0 ? "timeline-pointer-left timeline-pointer" : "timeline-pointer" }`} aria-hidden="true"></div>
<div className="p-6 bg-white rounded-md shadow-md sm:p-2">
<p className="pt-1">{project.description}</p>
</div>
</div>
</div>
))}
</div>
</div>
)
}
{project.tags.map( type => ( {type} ))} is the answer.