Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@
"signUp": "Sign up for a Mobility Database account or login to add or update a GTFS feed.",
"signUpAction": "Sign up for an account",
"loginSuccess": "You were successfully logged in, you can now add or update a feed.",
"emailVerificationRequired": "Please verify your email address to submit or update feeds.",
"dataTypeRequired": "Data format required",
"isOfficialFeedRequired": "Official feed required",
"feedLinkRequired": "Feed link required",
Expand Down
1 change: 1 addition & 0 deletions messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@
"signUp": "Sign up for a Mobility Database account or login to add or update a GTFS feed.",
"signUpAction": "Sign up for an account",
"loginSuccess": "You were successfully logged in, you can now add or update a feed.",
"emailVerificationRequired": "Veuillez vérifier votre adresse e-mail pour soumettre ou mettre à jour des flux.",
"dataTypeRequired": "Data format required",
"isOfficialFeedRequired": "Official feed required",
"feedLinkRequired": "Feed link required",
Expand Down
19 changes: 17 additions & 2 deletions src/app/[locale]/contribute/FeedSubmission/FeedSubmission.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import {
Typography,
} from '@mui/material';
import CheckIcon from '@mui/icons-material/Check';
import { selectIsAuthenticated } from '../../../store/profile-selectors';
import {
selectIsAuthenticated,
selectIsEmailVerified,
} from '../../../store/profile-selectors';
import { useTranslations } from 'next-intl';
import { useSearchParams } from 'next/navigation';
import FeedSubmissionForm from './Form';
Expand All @@ -24,6 +27,7 @@ function Component(): React.ReactElement {
searchParams.get('from') === 'registration',
);
const isAuthenticated = useSelector(selectIsAuthenticated);
const isEmailVerified = useSelector(selectIsEmailVerified);

return (
<Container component='main' sx={{ my: 0, mx: 'auto' }}>
Expand All @@ -42,7 +46,18 @@ function Component(): React.ReactElement {
</Button>
</>
)}
{isAuthenticated && (
{isAuthenticated && !isEmailVerified && (
<Box sx={{ my: 3 }}>
<Typography variant='h1'>{t('form.addOrUpdateFeed')}</Typography>
<Alert severity='warning' sx={{ my: 2 }}>
{t('form.emailVerificationRequired')}
</Alert>
<Button variant='contained' href='/verify-email'>
Verify Email
</Button>
</Box>
)}
{isAuthenticated && isEmailVerified && (
<>
{showLoginSuccess && (
<Alert
Expand Down
14 changes: 13 additions & 1 deletion src/app/components/AccessRequiredPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function AccessRequiredPopover({
}: AccessRequiredPopoverProps): React.ReactElement {
const t = useTranslations('common');
const pathname = usePathname();
const { isAuthenticated } = useAuthSession();
const { isAuthenticated, isEmailVerified } = useAuthSession();

return (
<Popover
Expand Down Expand Up @@ -96,6 +96,18 @@ export default function AccessRequiredPopover({
<LoginButton pathname={pathname} onClose={onClose} />
</Suspense>
)}
{isAuthenticated && !isEmailVerified && (
<Button
variant='contained'
disableElevation
component={Link}
sx={{ width: '100%', mb: 1 }}
href='/verify-email'
onClick={onClose}
>
{t('verifyEmail') ?? 'Verify Email'}
</Button>
)}
<Button
variant='outlined'
disableElevation
Expand Down
5 changes: 5 additions & 0 deletions src/app/components/AuthSessionProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ interface AuthSession {
uid: string | null;
email: string | null;
isAuthenticated: boolean;
isEmailVerified: boolean;
displayName?: string | null;
}

Expand All @@ -45,6 +46,7 @@ const AuthReadyContext = createContext<AuthSession>({
uid: null,
email: null,
isAuthenticated: false,
isEmailVerified: false,
displayName: null,
});

Expand Down Expand Up @@ -84,6 +86,7 @@ export function AuthSessionProvider({
uid: null,
email: null,
isAuthenticated: false,
isEmailVerified: false,
displayName: null,
});
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
Expand Down Expand Up @@ -119,6 +122,7 @@ export function AuthSessionProvider({
uid: user.uid,
email: user.email ?? null,
isAuthenticated: !user.isAnonymous,
isEmailVerified: user.emailVerified ?? false,
displayName: user.displayName ?? null,
});
syncSession(user.uid, user.isAnonymous);
Expand All @@ -139,6 +143,7 @@ export function AuthSessionProvider({
uid: null,
email: null,
isAuthenticated: false,
isEmailVerified: false,
displayName: null,
});
dispatch(anonymousLogin());
Expand Down
5 changes: 3 additions & 2 deletions src/app/screens/Feed/components/ClientSubscribeControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export default function ClientSubscribeControls({
feedId,
}: ClientSubscribeControlsProps): React.ReactElement | null {
const { config } = useRemoteConfig();
const { isAuthenticated } = useAuthSession();
const { isAuthenticated, isEmailVerified } = useAuthSession();
const {
flags: { isNotificationsEnabled },
isResolved: areFlagsResolved,
Expand All @@ -105,7 +105,8 @@ export default function ClientSubscribeControls({
// Showing the lock in that window would be a wrong answer the user can click.
const isAccessPending = isAuthenticated && !areFlagsResolved;
const hasNoAccess =
!isAccessPending && (!isAuthenticated || !isNotificationsEnabled);
!isAccessPending &&
(!isAuthenticated || !isEmailVerified || !isNotificationsEnabled);

const [snackbarMessage, setSnackbarMessage] = useState('');
const [snackbarSeverity, setSnackbarSeverity] = useState<
Expand Down
4 changes: 4 additions & 0 deletions src/app/store/profile-selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export const selectIsAuthenticated = (state: RootState): boolean =>
export const selectIsAnonymous = (state: RootState): boolean =>
state.userProfile.status === 'anonymous_login';

export const selectIsEmailVerified = (state: RootState): boolean =>
state.userProfile.user?.isEmailVerified ??
state.userProfile.status === 'authenticated';

export const selectUserProfileStatus = (state: RootState): string =>
state.userProfile.status;

Expand Down