Collapsible Card Component tailwind - javascript

I'm trying to use tailwindcss to create a collapsible card component similar to the pre-made component in Material-UI (reference).
I'm new to tailwindcss and can't quite figure out how to make the transition smooth. I have toggled the card using state.
The I am having trouble with is underneath the 'Image' component.
import Image from "next/image";
import { useRouter } from "next/router";
import { useState } from "react";
import { ChevronDownIcon } from "#heroicons/react/solid";
const ProjectCard = ({
title,
descriptionStart,
descriptionFull,
link,
image,
}) => {
const router = useRouter();
const [readMore, setReadMore] = useState(false);
return (
<div className='relative shadow-md flex flex-col bg-white rounded-lg p-4 m-4 space-y-8'>
<h1>{title}</h1>
<Image
src={image}
alt={title}
height={100}
width={100}
objectFit='contain'
/>
<div className='transition-all duration-200 ease-in-out'>
<p>{descriptionStart}</p>
<p
className={` ${
readMore
? "inline-flex transition-all ease-in-out duration-150"
: " hidden transition-all ease-in-out duration-150"
} `}>
{descriptionFull}
</p>
</div>
<button
className='bg-gray-100 w-[150px] h-[30px] rounded-lg shadow-lg mx-auto'
onClick={() => router.push(`${link}`)}>
View Project
</button>
<button
onClick={() => setReadMore(!readMore)}
className='absolute bottom-[16px] right-[16px]'>
{readMore ? (
<ChevronDownIcon className='rotate-180 h-6 transition-all duration-150 ease-in' />
) : (
<ChevronDownIcon className='h-6 transition-all duration-150 ease-in' />
)}
</button>
</div>
);
};
export default ProjectCard;

Related

Applying Tailwind overflow behavior to only one child element

I'm using Tailwind to style a React component called "BlurImage" which displays an image by default and then on hover removes the image and displays a button at the bottom of the component and a text box at the top that has overflow-y-auto behavior to allow for scrolling if the text grows too long.
By default, the overflow responsibility is given to the body as discussed here and so I need to give the parent top-level div of BlurImage overflow as well. This causes both the text and the button to be scrollable. Is there a way to avoid having the button scroll?
This seems like it should be a common situation - I can imagine using this concept to write self-contained components that have a header/footer and some scrollable content as well. Unfortunately, I can't find much addressing this in the Tailwind docs or online.
I appreciate any suggestions! Here is the component code that I currently have:
import Image from 'next/image';
import cn from 'classnames';
import { useState } from 'react';
import { ImageInfo } from '../../types/images';
import Button from './button';
import { useRouter } from 'next/router';
type BlurImageProps = {
image: ImageInfo;
};
const BlurImage = ({ image }: BlurImageProps): JSX.Element => {
const [isLoading, setLoading] = useState(true);
return (
<div className="group shrink-0 h-40 w-40 relative aspect-w-1 aspect-h-1 overflow-hidden rounded-lg xl:aspect-w-7 xl:aspect-h-8 drop-shadow-xl bg-black">
<Image
alt=""
src={image.url}
width={512}
height={512}
className={cn(
'flex h-full duration-700 ease-in-out group-hover:opacity-20',
{
'scale-110 blur-2xl grayscale': isLoading,
'scale-100 blur-0 grayscale-0': !isLoading,
},
)}
onLoadingComplete={() => setLoading(false)}
/>
{!isLoading && (
<div className="absolute bottom-0 left-0 overflow-y-scroll items-center justify-center w-full h-full align-middle text-center px-2 opacity-0 duration-700 ease-in-out group-hover:opacity-100">
<a href={image.url}>
<p className="text-base text-white mb-2">
{image.prompt}
</p>
</a>
<Button
className="flex-shrink-0 px-2 py-2 text-sm font-bold text-white rounded bg-green-500"
type="button"
text="click me"
isSubmit={true}
onClick={() => console.log("clicked")}
/>
</div>
)}
</div>
);
};
export default BlurImage;

Button Function Not calling From Another file in React

I need to call CutomerDashboard.js file's "toggleIsTrucated" function and "isTruncated" to CustomerNotice.js files button onClick and text change places, How can I call that?
(In this customer dashboard file I'm creating a Read function to show some extent of notice text)
import React, {useState,useEffect} from 'react';
import { Input, Row, Col, Button } from 'antd';
import {fetchDashboardMetrics} from "./DashboardApi";
import {items} from "./DashboardItems";
import axios from 'axios';
import CustomerNotice from "./CustomerNotice";
function Read ({children}) {
const text = children;
const [isTruncated, setIsTrucated] = useState(true);
const result = isTruncated ? text.slice(0,90) : text;
function toggleIsTrucated(){
setIsTrucated(!isTruncated);
}
return (
<div>
{result}....
</div>
);
}
const CustomerDashboard = () => {
const [features, setFeatures] = useState(items);
const source = axios.CancelToken.source()
const [notice, setNotice] = useState(<Read>Customer Notice: Optimism Is Invaluable For The Meaningful Life. With A Firm Belief In A Positive Future You Can Throw Yourself Into The Service Of That Which Is Larger Than You Are. -Martin Seligman-</Read>);
const [noticeVisibility, setNoticeVisibility] = useState(true);
useEffect(() => {
fetchDashboardMetrics(features, setFeatures,source.token)
return (() => {
source.cancel();
})
}, []);
return (
<>
<div className='md:pl-8 sm:pl-0'>
<div className='my-5 '>
<p className='mb-8'>My Account - Dashboard Overview</p>
{noticeVisibility && <CustomerNotice notice={notice} setNoticeVisibility={setNoticeVisibility}/>}
</div>
<ul role="list" className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{features.map((feature) => (
<li key={feature.name} className="col-span-1 bg-white rounded-lg shadow divide-y divide-gray-200 relative">
<div className="w-full flex items-center justify-between p-6 space-x-6">
<div className="flex-1 truncate">
<div className="flex items-center space-x-3 justify-between">
<h3 className="text-gray-900 text-lg truncate">{feature.name}</h3>
{feature.isNew && (
<div className="absolute -top-2 -right-2 p-1 px-4 text-white text-sm bg-red-500">
New
</div>
)}
</div>
</div>
</div>
<div>
<div className={'mx-4 mt-2 mb-3 '}>
{feature.details.map((singleDetail) => {
return (
<div className={'flex justify-between text-base'}>
<span>{singleDetail.name}</span>
<span>{singleDetail.value}</span>
</div>
)
})}
</div>
</div>
</li>
))}
</ul>
</div>
</>
)
}
export default CustomerDashboard;
import React, {useState,useEffect} from 'react';
import {XIcon} from "#heroicons/react/solid";
const CustomerNotice = ({notice, setNoticeVisibility}) => {
return (
<div>
<div className="mt-8 pb-2 sm:pb-5">
<div className="max-w-7xl mx-auto px-2 sm:px-6 lg:px-8">
<div className="p-2 rounded-lg bg-orange-600 shadow-lg sm:p-3">
<div className="flex items-center justify-between flex-wrap">
<div className="w-0 flex-1 flex items-center">
<p className="ml-3 font-medium text-white truncate">
<span className="md:inline">{notice}</span>
</p>
</div>
<div className="order-3 mt-2 flex-shrink-0 w-full sm:order-2 sm:mt-0 sm:w-auto">
<a
href="#"
className="flex items-center justify-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-orange-600 bg-white hover:bg-orange-50"
>
<button onClick={toggleIsTrucated}>{isTruncated ? "Read More" : "Read Less"}</button>
</a>
</div>
<div className="order-2 flex-shrink-0 sm:order-3 sm:ml-2">
<button
onClick={() => setNoticeVisibility(false)}
type="button"
className="-mr-1 flex p-2 rounded-md hover:bg-orange-500 focus:outline-none focus:ring-2 focus:ring-white"
>
<span className="sr-only">Dismiss</span>
<XIcon className="h-6 w-6 text-white" aria-hidden="true"/>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default CustomerNotice;
If this is not possible please suggest me a possible way.
Instead of doing a bunch of hacks, I would recommend simplifying the structure of your components.
import { useState } from 'react'
export default function CustomerDashboard() {
// I am not sure why you want to keep notice in state,
// because in your example you did not call setNotice
const [notice, setNotice] = useState(`
Customer Notice: Optimism Is Invaluable For The Meaningful Life.
With A Firm Belief In A Positive Future You Can Throw Yourself Into The Service
Of That Which Is Larger Than You Are. -Martin Seligman
`)
const [isNoticeVisible, setIsNoticeVisible] = useState(true)
return (
<div>
<h1>My Account - Dashboard Overview</h1>
{isNoticeVisible && (
<CustomerNotice
notice={notice}
setIsNoticeVisible={setIsNoticeVisible}
/>
)}
</div>
)
}
function CustomerNotice(props) {
const { notice, setIsNoticeVisible } = props
const [isTruncated, setIsTruncated] = useState(true)
function toggleIsTruncated() {
setIsTruncated(!isTruncated)
}
return (
<div>
<Read text={notice} isTruncated={isTruncated} />
<button onClick={toggleIsTruncated}>
{isTruncated ? 'Read More' : 'Read Less'}
</button>
<button onClick={() => setIsNoticeVisible(false)}>Dismiss</button>
</div>
)
}
function Read(props) {
const { text, isTruncated } = props
const result = isTruncated ? text.slice(0, 90) : text
return <div>{result}....</div>
}
List of the things that were bad in your code.
Keeping the component instance in the state. It is hard to manage. Even your simple case proves that.
Keeping the toggleIsTruncated function inside the Read component. I think we should keep it outside and pass only 2 props to the Read component. I enable exposed only two things
const { text, isTruncated } = props
As you can see it is easy to maintain and allow us to do whatever we want.
PS. If my review and example were helpful please leave the thumbs up.

Prevent react from restarting the css animation on route change

In my react app I have a file called SecondaryLayout.js
const SecondaryLayout = ({children, className, ...rest}) => {
return (
<>
<Sidebar />
<main className={['seconday_layout__container', className].join('')} {...rest}>
{children}
</main>
</>
);
};
Sidebar.js:
const Sidebar = () => {
const {user} = useSelector(state => state.auth);
return (
<div className="bg-white py-4 px-2 fixed h-screen shadow-lg secondary_layout__sidebar">
<div className="h-full flex flex-col justify-between items-center">
<Link to="/"><h1 className="font-pacifico text-white px-2.5 py-1 bg-blue-700 rounded-full text-xl -mb-5">P</h1></Link>
<div className="flex flex-col space-y-2">
<NavLink to="/user/dashboard" className="px-2.5 py-1.5 rounded-lg shadow-md" activeClassName="bg-blue-700 shadow-lg text-white"><TemplateIcon className="inline w-4 h-4 -mt-1"/></NavLink>
<NavLink to="/user/listings" className="px-2.5 py-1.5 rounded-lg shadow-md" activeClassName="bg-blue-700 shadow-lg text-white"><ViewListIcon className="inline w-4 h-4 -mt-1"/></NavLink>
<NavLink to="/user/address" className="px-2.5 py-1.5 rounded-lg shadow-md" activeClassName="bg-blue-700 shadow-lg text-white"><LocationMarkerIcon className="inline w-4 h-4 -mt-1"/></NavLink>
<NavLink to="/user/profile" className="px-2.5 py-1.5 rounded-lg shadow-md" activeClassName="bg-blue-700 shadow-lg text-white"><CogIcon className="inline w-4 h-4 -mt-1"/></NavLink>
</div>
<Avatar name={user.username} image={user.image} />
</div>
</div>
);
};
The sidebar has a css animation, and 3 NavLinks, every time I click on a link, the css animation restarts, the behavior that I want is the sidebar to only fade in once, and stay fixed even when I click on a navlink, I tried to wrap my sidebar component with React.memo() but that didn't fix the issue
Edit:
Let's say the user navigates to /user/dashboard, or /user/profile, all these routes should always render the sidebar
Example
Dashboard.js
import React from 'react';
import { Helmet } from 'react-helmet';
import SecondaryLayout from '../../layouts/SecondaryLayout';
const Dashboard = () => {
return (
<SecondaryLayout>
<Helmet>
<title>My Dashboard</title>
</Helmet>
Dashboard
</SecondaryLayout>
);
};
export default Dashboard;
I think I managed to fix the issue, what I was doing is to wrap every component by the secondary layout, what I have done is to move the Secondary Layout to wrap around the route component itself, and not around the component being rendered by the route, i.e: <Route .... /></Route .... />

Use `ListBox` from `#headlessui/react` with Mobx?

Before using ListBox:
store/index.ts
import { action, makeObservable, observable } from 'mobx'
import type { IFrameItStore, TrafficSignal } from '#/types/index'
export class FrameItStore implements IFrameItStore {
trafficSignal: TrafficSignal = {
shape: 'circle',
}
constructor() {
makeObservable(this, {
trafficSignal: observable,
updateTrafficSignal: action.bound,
})
}
updateTrafficSignal({ shape }: TrafficSignal) {
if (shape) this.trafficSignal.shape = shape
}
}
Shape.tsx
import { observer } from 'mobx-react'
import * as React from 'react'
import { useFrameItStore } from '#/store/index'
import type { TrafficSignalShape } from '#/types/index'
export const Shape = observer(() => {
const frameItStore = useFrameItStore()
return (
<>
<label htmlFor="shape" className="mb-1 text-sm font-medium text-blue-gray-500">
Shape
</label>
<select
id="shape"
className="block w-full px-3 py-2 mb-2 bg-white border border-gray-300 rounded-md shadow-sm text-blue-gray-500 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
value={frameItStore.trafficSignal.shape}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
const shape = e.target.value as TrafficSignalShape
frameItStore.updateTrafficSignal({ shape })
}}
>
<option value="circle">Circle</option>
<option value="square">Square</option>
</select>
</>
)
})
App.tsx
<Shape />
After using ListBox:
Select.tsx
import * as React from 'react'
import { Listbox, Transition } from '#headlessui/react'
import clsx from 'clsx'
import { Selector, Check } from '#/components/icons/index'
type Option = {
id: string
name: string
img: string
}
interface IProps {
label?: string
options: Array<Option>
}
export const Select = ({ label, options }: IProps) => {
const [selectedOption, setSelectedOption] = React.useState<Option>(options[0])
return (
<Listbox value={selectedOption} onChange={setSelectedOption}>
{({ open }) => (
<>
<Listbox.Label className="mb-1 text-sm font-medium text-blue-gray-500">
{label}
</Listbox.Label>
<div className="relative mt-1">
<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left bg-white border border-gray-300 rounded-md shadow-sm cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<span className="flex items-center">
<img
src={selectedOption.img}
alt={selectedOption.name}
className="flex-shrink-0 w-6 h-6 rounded-full"
/>
<span className="block ml-3 truncate">{selectedOption.name}</span>
</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 ml-3 pointer-events-none">
<Selector />
</span>
</Listbox.Button>
<div className="absolute w-full mt-1 bg-white rounded-md shadow-lg">
<Transition
show={open}
leave="transition duration-100 ease-in"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options
static
className="py-1 overflow-auto text-base rounded-md max-h-56 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
>
{options.map((option) => (
<Listbox.Option as={React.Fragment} key={option.id} value={option}>
{({ active, selected }) => (
<li
className={clsx('relative py-2 pl-3 cursor-default select-none pr-9', {
'text-white bg-indigo-600': active,
'text-gray-900': !active,
})}
>
<div className="flex items-center">
<img
src={option.img}
alt={option.name}
className="flex-shrink-0 w-6 h-6 rounded-full"
/>
<span
className={clsx('ml-3 block truncate', {
'font-semibold': selected,
'font-normal': !selected,
})}
>
{option.name}
</span>
</div>
{selected && (
<span
className={clsx('absolute inset-y-0 right-0 flex items-center pr-4', {
'text-white': active,
'text-indigo-600': !active,
})}
>
<Check />
</span>
)}
</li>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</div>
</>
)}
</Listbox>
)
}
App.tsx
const shapes = [
{
id: '1',
name: 'Circle',
img:
'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
{
id: '2',
name: 'Square',
img:
'https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
]
<Select label="Shape" options={shapes} />
How do I convert the After part to use MobX like the Before part?
I tried passing value & onChange as it is in the Before part to Select like:
App.tsx
<Select
label="Shape"
options={shapes}
value={frameItStore.trafficSignal.shape}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
const shape = e.target.value as TrafficSignalShape
frameItStore.updateTrafficSignal({ shape })
}}
/>
Select.tsx
interface IProps {
label?: string
value: any
onChange: (value: any) => void
options: Array<Option>
}
export const Select = ({ label, options, value, onChange }: IProps) => {
const [selectedOption, setSelectedOption] = React.useState<Option>(options[0])
return (
<Listbox value={value} onChange={onChange}>
.
.
.
</Listbox>
)
}
But it doesn't select anything & I don't know what to do of selectedOption?
Alright I solved it. Removed the local hook state & just used the MobX state. Also, had 1 minor issue. I was setting the value as uppercase in the store when the store originally had lowercase values. The uppercase values were only for display in the UI.
Here's the modified code that works:
App.tsx
<Select
label="Shape"
options={shapes}
value={shapes.filter({ name }) => name.toLowerCase() === frameItStore.trafficSignal.shape)[0]}
onChange={(value) => {
const shape = value.toLowerCase() as TrafficSignalShape
frameItStore.updateTrafficSignal({ shape })
}}
/>
Select.tsx
import * as React from 'react'
import { Listbox, Transition } from '#headlessui/react'
import clsx from 'clsx'
import { Selector, Check } from '#/components/icons/index'
type Option = {
id: string
name: string
img: string
}
interface IProps {
label?: string
value: Option
onChange: (name: string) => void
options: Array<Option>
}
export const Select = ({ label, options, value, onChange }: IProps) => {
return (
<Listbox
value={value}
onChange={(value: Option) => {
onChange(value.name)
}}
>
{({ open }) => (
<>
<Listbox.Label className="mb-1 text-sm font-medium text-blue-gray-500">
{label}
</Listbox.Label>
<div className="relative mt-1">
<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left bg-white border border-gray-300 rounded-md shadow-sm cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<span className="flex items-center">
<img
src={value.img}
alt={value.name}
className="flex-shrink-0 w-6 h-6 rounded-full"
/>
<span className="block ml-3 truncate">{value.name}</span>
</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 ml-3 pointer-events-none">
<Selector />
</span>
</Listbox.Button>
<div className="absolute z-10 w-full mt-1 bg-white rounded-md shadow-lg">
<Transition
show={open}
leave="transition duration-100 ease-in"
leaveFrom="transform opacity-100"
leaveTo="transform opacity-0"
>
<Listbox.Options
static
className="py-1 overflow-auto text-base rounded-md max-h-56 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
>
{options.map((option) => {
return (
<Listbox.Option as={React.Fragment} key={option.id} value={option}>
{({ active, selected }) => {
return (
<li
className={clsx(
'relative py-2 pl-3 cursor-default select-none pr-9',
{
'text-white bg-indigo-600': active,
'text-gray-900': !active,
}
)}
>
<div className="flex items-center">
<img
src={option.img}
alt={option.name}
className="flex-shrink-0 w-6 h-6 rounded-full"
/>
<span
className={clsx('ml-3 block truncate', {
'font-semibold': selected,
'font-normal': !selected,
})}
>
{option.name}
</span>
</div>
{selected && (
<span
className={clsx(
'absolute inset-y-0 right-0 flex items-center pr-4',
{
'text-white': active,
'text-indigo-600': !active,
}
)}
>
<Check />
</span>
)}
</li>
)
}}
</Listbox.Option>
)
})}
</Listbox.Options>
</Transition>
</div>
</div>
</>
)}
</Listbox>
)
}

Why my redux state is go back to intial value on Page Refresh?

After SignIn, my authState becomes true, which is expected. and then It redirected to the home page. But after that If I refresh the page, my state goes back to initial value. what could be the reason of this?
Login Component:
import React, { useState, useEffect } from 'react';
import { toast } from 'react-toastify';
import axios from 'axios';
import { Redirect } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { setCurrentUser } from 'src/store/reducer/authReducer';
import jwtDecode from 'jwt-decode';
import { authenticate, isAuth } from '../helpers/auth';
import Protection from '../assets/Protection.svg';
import useInputState from '../hooks/useInputState';
const Login = (props) => {
const auth = useSelector((state) => state.auth);
const [submitted, setSubmitted] = useState(false);
const [btnText, setBtnText] = useState('Sign In');
const dispatch = useDispatch();
const { location } = props;
const initialValue = { name: '', email: '', password: '' };
const [state, onChangeHandler, reset] = useInputState(initialValue);
const { email, password } = state;
// submit data to backend
const handleSubmit = async (e) => {
e.preventDefault();
try {
const res = await axios.post(`${process.env.API_URL}/api/signin`, {
email,
password,
});
reset();
setSubmitted(true);
setBtnText('Submitted');
const { token: jwtToken } = res.data;
localStorage.setItem('jwtToken', jwtToken);
const decoded = jwtDecode(jwtToken);
dispatch(setCurrentUser(decoded));
} catch (err) {
const { errors } = err.response.data;
for (const error of errors) {
const msg = Object.values(error).toString();
toast.error(msg);
}
}
};
useEffect(() => {
if (location.message) {
toast.success(location.message);
}
}, [location.message]);
if (submitted && auth.isAuthenticated) {
return <Redirect to={{ pathname: '/', message: 'You are signed in' }} />;
}
return (
<div className="min-h-screen bg-gray-100 text-gray-900 flex justify-center">
<div className="max-w-screen-xl m-0 sm:m-20 bg-white shadow sm:rounded-lg flex justify-center flex-1">
<div className="lg:w-1/2 xl:w-5/12 p-6 sm:p-12">
<div className="mt-12 flex flex-col items-center">
<h1 className="text-2xl xl:text-3xl font-extrabold">
Sign In for MernAuth
</h1>
<form
className="w-full flex-1 mt-8 text-indigo-500"
onSubmit={handleSubmit}
>
<div className="mx-auto max-w-xs relative">
<input
className="w-full px-8 py-4 rounded-lg font-medium bg-gray-100 border-gray-200 placeholder-gray-500 text-sm focus:outline-none focus:border-gray-400 focus:bg-white mt-5"
type="email"
name="email"
placeholder="Email"
onChange={onChangeHandler}
value={email}
/>
<input
className="w-full px-8 py-4 rounded-lg font-medium bg-gray-100 border-gray-200 placeholder-gray-500 text-sm focus:outline-none focus:border-gray-400 focus:bg-white mt-5"
type="password"
name="password"
placeholder="Password"
onChange={onChangeHandler}
value={password}
/>
<button
className="mt-5 tracking-wide font-semibold bg-indigo-500 text-gray-100 w-full py-4 rounded-lg hover:bg-indigo-700 transition-all duration-300 ease-in-out flex items-center justify-center focus:shadow-outline focus:outline-none border-none outline-none"
type="submit"
>
<i className="fas fa-user-plus fa 1x w-6 -ml-2" />
<span className="ml-3">{btnText}</span>
</button>
</div>
<div className="my-12 border-b text-center">
<div className="leading-node px-2 inline-block text-sm text-gray-600 tracking-wide font-medium bg-white transform tranlate-y-1/2">
Or sign in with email or social login
</div>
</div>
<div className="flex flex-col items-center">
<a
className="w-full max-w-xs font-bold shadow-sm rounded-lg py-3
bg-indigo-100 text-gray-800 flex items-center justify-center transition-all duration-300 ease-in-out focus:outline-none hover:shadow focus:shadow-sm focus:shadow-outline mt-5"
href="/login"
target="_self"
>
<i className="fas fa-sign-in-alt fa 1x w-6 -ml-2 text-indigo-500" />
<span className="ml-4">Sign Up</span>
</a>
</div>
</form>
</div>
</div>
<div className="flex-1 bg-indigo-100 text-center hidden lg:flex">
<div
className="m-12 xl:m-16 w-full bg-contain bg-center bg-no-repeat"
style={{ backgroundImage: `url(${Protection})` }}
/>
</div>
</div>
</div>
);
};
export default Login;
my home component
import React, { useEffect } from 'react';
import { toast } from 'react-toastify';
const App = (props) => {
const { location } = props;
useEffect(() => {
if (location.message) {
toast.success(location.message);
}
}, [location.message]);
return <div>App</div>;
};
export default App;
I don't want the state to go back to its initial value on page refresh.
Your data is not persisted. Save the user token in the localStorage and when the app is initializing verify the localStorage and if there have value simply populate the store with this data.
Since you want to store user token, I would suggest that you use a cookie to store it, here is a link where you can find how to create and use a cookie.

Categories

Resources