Skip to content

Commit

Permalink
Update auth component
Browse files Browse the repository at this point in the history
  • Loading branch information
harishmohanraj committed Apr 12, 2024
1 parent 505b12c commit fc65f70
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 83 deletions.
2 changes: 1 addition & 1 deletion app/main.wasp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ app OpenSaaS {
},
},
onAuthFailedRedirectTo: "/login",
onAuthSucceededRedirectTo: "/",
onAuthSucceededRedirectTo: "/chat",
},
db: {
system: PostgreSQL,
Expand Down
19 changes: 18 additions & 1 deletion app/src/client/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,24 @@ export default function App({ children }: { children: ReactNode }) {
<TosAndMarketingEmailsModal />
</>
) : (
children
<>
{isAdminDashboard ? (
children
) : (
<div className='relative flex flex-col min-h-screen justify-between'>
{shouldDisplayAppNavBar && <AppNavBar />}
{children}
<div>
<Footer />
<div className='flex items-center h-20 bg-airt-footer-copyrights'>
<p className='text-center w-full text-sm text-airt-font-base opacity-50'>
© 2024 airt. All rights reserved.
</p>
</div>
</div>
</div>
)}
</>
)}
</>
) : (
Expand Down
11 changes: 7 additions & 4 deletions app/src/client/app/AccountPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { STRIPE_CUSTOMER_PORTAL_LINK } from '../../shared/constants';
import { TierIds } from '../../shared/constants';
import Button from '../components/Button';
import FreeTrialButton from '../components/FreeTrialButton';
import { MarketingEmailPreferenceSwitcher } from '../components/MarketingEmailPreferenceSwitcher';

export default function AccountPage({ user }: { user: User }) {
return (
Expand Down Expand Up @@ -63,10 +64,12 @@ export default function AccountPage({ user }: { user: User }) {
)}
</div>
<div className='py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-5 sm:px-6'>
<dt className='text-sm font-medium text-airt-font-base dark:text-white'>About</dt>
<dd className='mt-1 text-sm text-airt-font-base dark:text-airt-font-base sm:col-span-2 sm:mt-0'>
I'm a cool customer.
</dd>
<dt className='text-sm font-medium text-airt-font-base'>I agree to receiving marketing emails</dt>
<>
<MarketingEmailPreferenceSwitcher
hasSubscribedToMarketingEmails={user.hasSubscribedToMarketingEmails}
/>
</>
</div>
</dl>
</div>
Expand Down
22 changes: 5 additions & 17 deletions app/src/client/auth/Auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const MessageSuccess = styled(Message, {
});

const logoStyle = {
height: '6rem',
height: '3rem',
};

const Container = styled('div', {
Expand Down Expand Up @@ -75,24 +75,14 @@ function Auth({

// const title = titles[state];

const socialButtonsDirection =
socialLayout === 'vertical' ? 'vertical' : 'horizontal';
const socialButtonsDirection = socialLayout === 'vertical' ? 'vertical' : 'horizontal';

return (
<div className={customTheme}>
<div>
{logo && (
<img
className='mt-10 mx-auto'
style={logoStyle}
src={logo}
alt='Capt’n.ai'
/>
)}
{logo && <img className='mt-10 mx-auto' style={logoStyle} src={logo} alt='Capt’n.ai' />}
{/* <HeaderText>{title}</HeaderText> */}
<p className='mt-7 text-2xl'>
{state === 'signup' ? titles.signup : titles.login}
</p>
<p className='mt-7 text-2xl'>{state === 'signup' ? titles.signup : titles.login}</p>
</div>

{/* {errorMessage && (
Expand All @@ -103,9 +93,7 @@ function Auth({
</MessageError>
)} */}
{successMessage && <MessageSuccess>{successMessage}</MessageSuccess>}
<AuthContext.Provider
value={{ isLoading, setIsLoading, setErrorMessage, setSuccessMessage }}
>
<AuthContext.Provider value={{ isLoading, setIsLoading, setErrorMessage, setSuccessMessage }}>
{(state === 'login' || state === 'signup') && (
<LoginSignupForm
state={state}
Expand Down
37 changes: 10 additions & 27 deletions app/src/client/auth/LoginSignupForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ const SocialAuthButtons = styled('div', {
const googleSignInUrl = `${config.apiUrl}/auth/google/login`;

export const checkBoxErrMsg = {
title:
"To proceed, please ensure you've accepted our Terms & Conditions and Privacy Policy.",
title: "To proceed, please ensure you've accepted our Terms & Conditions and Privacy Policy.",
description: '',
};

Expand All @@ -65,8 +64,7 @@ export const LoginSignupForm = ({
additionalSignupFields?: any;
errorMessage?: any;
}) => {
const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } =
useContext(AuthContext);
const { isLoading, setErrorMessage, setSuccessMessage, setIsLoading } = useContext(AuthContext);
const [tocChecked, setTocChecked] = useState(false);
const [marketingEmailsChecked, setMarketingEmailsChecked] = useState(false);
const [loginFlow, setLoginFlow] = useState(state);
Expand All @@ -87,26 +85,18 @@ export const LoginSignupForm = ({
setTocChecked(event.target.checked);
};

const handleMarketingEmailsChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {
const handleMarketingEmailsChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setMarketingEmailsChecked(event.target.checked);
};

const updateLocalStorage = () => {
localStorage.removeItem('hasAcceptedTos');
localStorage.removeItem('hasSubscribedToMarketingEmails');
localStorage.setItem('hasAcceptedTos', JSON.stringify(tocChecked));
localStorage.setItem(
'hasSubscribedToMarketingEmails',
JSON.stringify(marketingEmailsChecked)
);
localStorage.setItem('hasSubscribedToMarketingEmails', JSON.stringify(marketingEmailsChecked));
};

const handleClick = (
event: React.MouseEvent<HTMLButtonElement>,
googleSignInUrl: string
) => {
const handleClick = (event: React.MouseEvent<HTMLButtonElement>, googleSignInUrl: string) => {
event.preventDefault();
if (loginFlow === State.Login) {
updateLocalStorage();
Expand All @@ -121,8 +111,7 @@ export const LoginSignupForm = ({
}
};

const googleBtnText =
loginFlow === State.Login ? 'Sign in with Google' : 'Sign up with Google';
const googleBtnText = loginFlow === State.Login ? 'Sign in with Google' : 'Sign up with Google';

return (
<>
Expand All @@ -139,9 +128,7 @@ export const LoginSignupForm = ({
<SocialAuthButtons gap='large' direction={socialButtonsDirection}>
<button
className='gsi-material-button'
onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
handleClick(event, googleSignInUrl)
}
onClick={(event: React.MouseEvent<HTMLButtonElement>) => handleClick(event, googleSignInUrl)}
>
<div className='gsi-material-button-state'></div>
<div className='gsi-material-button-content-wrapper'>
Expand Down Expand Up @@ -172,22 +159,18 @@ export const LoginSignupForm = ({
<path fill='none' d='M0 0h48v48H0z'></path>
</svg>
</div>
<span className='gsi-material-button-contents'>
{googleBtnText}
</span>
<span className='gsi-material-button-contents'>{googleBtnText}</span>
<span style={{ display: 'none' }}>{googleBtnText}</span>
</div>
</button>
</SocialAuthButtons>
</SocialAuth>
<div className='flex items-center justify-center'>
<span className='text-sm block'>
{loginFlow === State.Login
? "Don't have an account? "
: 'Already have an account? '}
{loginFlow === State.Login ? "Don't have an account? " : 'Already have an account? '}
<Link
to={loginFlow === State.Login ? '/signup' : '/login'}
className='no-underline hover:underline cursor-pointer'
className='no-underline hover:underline cursor-pointer text-airt-secondary'
>
{loginFlow === State.Login ? 'Sign up' : 'Sign in'}
</Link>
Expand Down
2 changes: 1 addition & 1 deletion app/src/client/components/AnimatedCharacterLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const AnimatedCharacterLoader: React.FC<AnimatedCharacterLoaderProps> = ({
>
<div
style={{ maxWidth: '800px', margin: 'auto' }}
className={`relative ml-3 block w-full p-4 pl-10 text-sm text-captn-light-cream border-captn-dark-blue rounded-lg ${bgColor} `}
className={`relative ml-3 block w-full p-4 pl-10 text-sm text-airt-font-base border-captn-dark-blue rounded-lg ${bgColor} `}
>
{showLogo && (
<span
Expand Down
80 changes: 80 additions & 0 deletions app/src/client/components/MarketingEmailPreferenceSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { useState } from 'react';

import { updateCurrentUser } from 'wasp/client/operations';
import NotificationBox from './NotificationBox';

export function MarketingEmailPreferenceSwitcher({
hasSubscribedToMarketingEmails,
}: {
hasSubscribedToMarketingEmails: boolean;
}) {
const [status, setStatus] = useState(hasSubscribedToMarketingEmails);
const [hasChanged, setHasChanged] = useState(false);
const [notificationType, setNotificationType] = useState<string | null>(null);

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setStatus(e.target.value === 'Yes');
setHasChanged(true);
};

const onClick = () => {
setNotificationType(null);
};

const handleClick = async (status: boolean) => {
try {
await updateCurrentUser({ hasSubscribedToMarketingEmails: status });
setNotificationType('success');
} catch (e) {
setNotificationType('error');
}
setHasChanged(false);
};

const notificationMsg =
notificationType === 'success'
? 'Your changes are saved successfully.'
: 'Something went wrong. Please try again later.';

return (
<>
{notificationType && (
<NotificationBox type={notificationType as 'success' | 'error'} onClick={onClick} message={notificationMsg} />
)}
<div className='mt-1 text-sm text-captn-dark-blue sm:col-span-1 sm:mt-0'>
<label className='mr-4'>
<input
type='radio'
value='Yes'
checked={status}
onChange={handleChange}
className='form-radio text-captn-light-blue mr-2 focus:ring-1 outline-none'
/>
Yes
</label>
<label>
<input
type='radio'
value='No'
checked={!status}
onChange={handleChange}
className='form-radio text-captn-light-blue mr-2 focus:ring-1 outline-none'
/>
No
</label>
</div>

<div className='ml-0 md:ml-4 flex-shrink-0 sm:col-span-1 sm:mt-0' style={{ height: '24px' }}>
<button
onClick={() => handleClick(status)}
disabled={!hasChanged}
className={`mt-4 md:-mt-10 no-underline rounded-md px-3.5 py-2.5 text-sm text-airt-font-base ring-1 ring-inset ring-gray-200 shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 dark:text-captn-light-cream bg-airt-primary hover:bg-opacity-85 ${
!hasChanged ? 'opacity-40 cursor-not-allowed' : ''
}`}
>
Save
</button>
</div>
</>
);
}
32 changes: 32 additions & 0 deletions app/src/client/components/NotificationBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';

interface NotificationBoxProps {
type: 'success' | 'error';
message: string;
onClick: () => void;
}

const NotificationBox: React.FC<NotificationBoxProps> = ({ type, message, onClick }) => {
const isSuccess = type === 'success';

return (
<div className='fixed inset-0 flex items-center justify-center z-50 p-16 backdrop-blur-sm bg-airt-font-base/30'>
<div className='bg-airt-primary rounded-lg shadow-lg p-8 m-4 max-w-sm mx-auto'>
<h2 className='text-xl font-bold mb-4 text-airt-font-base'>{isSuccess ? 'Success' : 'Error'}</h2>
<p className='text-airt-font-base'>{message}</p>
<div className='mt-4 text-right'>
<button
onClick={onClick}
className={`py-2 px-4 rounded text-airt-font-base focus:outline-none ${
isSuccess ? 'bg-airt-secondary' : 'bg-airt-secondary'
}`}
>
OK
</button>
</div>
</div>
</div>
);
};

export default NotificationBox;
26 changes: 5 additions & 21 deletions app/src/client/components/TosAndMarketingEmails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,39 +30,23 @@ const TosAndMarketingEmails: React.FC<TosAndMarketingEmailsProps> = ({
handleMarketingEmailsChange,
errorMessage,
}) => (
<div className='toc-marketing-checkbox-wrapper text-captn-light-cream'>
<div className='toc-marketing-checkbox-wrapper text-airt-font-base'>
<div className='mt-4'>
<label className='checkbox-container text-sm mb-2' htmlFor='toc'>
I agree to the{' '}
<Link
to='/toc'
className='no-underline hover:underline'
target='_blank'
>
<Link to='/toc' className='no-underline hover:underline text-airt-secondary' target='_blank'>
Terms & Conditions
</Link>{' '}
and{' '}
<Link
to='/privacy'
className='no-underline hover:underline'
target='_blank'
>
<Link to='/privacy' className='no-underline hover:underline text-airt-secondary' target='_blank'>
Privacy Policy
</Link>
<input
type='checkbox'
id='toc'
checked={tocChecked}
onChange={handleTocChange}
/>
<input type='checkbox' id='toc' checked={tocChecked} onChange={handleTocChange} />
<span className='checkmark'></span>
</label>
</div>
<div>
<label
className='checkbox-container text-sm mb-2'
htmlFor='marketingEmails'
>
<label className='checkbox-container text-sm mb-2' htmlFor='marketingEmails'>
I agree to receiving marketing emails
<input
type='checkbox'
Expand Down
Loading

0 comments on commit fc65f70

Please sign in to comment.