diff --git a/src/backend/apps/authentication/views.py b/src/backend/apps/authentication/views.py
index f55514916..d9f17ada0 100644
--- a/src/backend/apps/authentication/views.py
+++ b/src/backend/apps/authentication/views.py
@@ -6,6 +6,7 @@
from django.core.exceptions import ObjectDoesNotExist
from django.core.mail import EmailMultiAlternatives
from django.db.utils import IntegrityError
+from django.http import HttpResponseRedirect
from django.shortcuts import reverse
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes, force_str
@@ -128,7 +129,7 @@ def get(self, request, uidb64, token):
if user is not None and EmailVerificationTokenGenerator().check_token(user, token):
user.verified = True
user.save()
- return Response({'message': 'Email verified successfully'}, status=status.HTTP_200_OK)
+ return HttpResponseRedirect(env("FRONTEND_BASE_URL") + 'account') # Redirect to the account page
else:
return Response({'error': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST)
diff --git a/src/backend/apps/shared/views.py b/src/backend/apps/shared/views.py
index 4153aeeba..d8cf82a1a 100644
--- a/src/backend/apps/shared/views.py
+++ b/src/backend/apps/shared/views.py
@@ -143,7 +143,8 @@ def get(self, request, format=None):
if request.user.is_authenticated:
response = JsonResponse({
"username": request.user.username,
- "email": request.user.email
+ "email": request.user.email,
+ "verified": request.user.verified
})
else:
diff --git a/src/frontend/src/App.js b/src/frontend/src/App.js
index 58056c6a3..15c035f88 100644
--- a/src/frontend/src/App.js
+++ b/src/frontend/src/App.js
@@ -43,6 +43,7 @@ import ScrollToTop from './Components/shared/ScrollToTop';
// FontAwesome Stylesheet
import { config } from '@fortawesome/fontawesome-svg-core'
import '@fortawesome/fontawesome-svg-core/styles.css'
+import VerifyEmailPage from "./pages/VerifyEmailPage";
config.autoAddCss = false
// Variables
@@ -148,11 +149,13 @@ function App() {
if (data.username) {
ret.username = data.username;
ret.email = data.email;
+ ret.verified = data.verified;
}
setAuthContext((prior) => {
if (ret.loginStateKnown != prior.loginStateKnown) { return ret; }
if (ret.username != prior.username) { return ret; }
if (ret.email != prior.email) { return ret; }
+ if (ret.verified != prior.verified) { return ret; }
return prior;
});
})
@@ -199,6 +202,7 @@ function App() {
} />
} />
} />
+ } />
{/* Catch-all route for 404 errors */}
} />
} />
diff --git a/src/frontend/src/pages/AccountPage.js b/src/frontend/src/pages/AccountPage.js
index f948e5049..79d6f309e 100644
--- a/src/frontend/src/pages/AccountPage.js
+++ b/src/frontend/src/pages/AccountPage.js
@@ -7,7 +7,6 @@ import Container from 'react-bootstrap/Container';
// Internal imports
import { AuthContext } from '../App';
-import { sendVerificationEmail } from "../Components/data/user";
import Footer from '../Footer.js';
import PageHeader from '../PageHeader';
@@ -33,7 +32,18 @@ export default function AccountPage() {
- Send Verification Email
+
+
Email Address
+
{authContext.email}
+
+ {!authContext.verified &&
+
+ This email address has not been verified. Email notifications for
+ saved routes will be disabled until verification
+ is complete.
+
+ }
+
diff --git a/src/frontend/src/pages/AccountPage.scss b/src/frontend/src/pages/AccountPage.scss
index 5cee5d2bf..5b044b004 100644
--- a/src/frontend/src/pages/AccountPage.scss
+++ b/src/frontend/src/pages/AccountPage.scss
@@ -1 +1,22 @@
@import "../styles/variables.scss";
+
+.account-page {
+ .email-address {
+ .email, .header {
+ font-size: 1.1rem;
+ font-weight: 700;
+ color: $MyAccountHeader;
+ }
+
+ .email {
+ font-weight: 400;
+ }
+
+ .not-verified {
+ background-color: $MyAccountWarning;
+ color: $MyAccountWarningText;
+ padding: 0.5rem 1rem;
+ font-size: 0.875rem;
+ }
+ }
+}
diff --git a/src/frontend/src/pages/SavedRoutesPage.js b/src/frontend/src/pages/SavedRoutesPage.js
index 4cfb4b6ce..8963c6784 100644
--- a/src/frontend/src/pages/SavedRoutesPage.js
+++ b/src/frontend/src/pages/SavedRoutesPage.js
@@ -1,6 +1,9 @@
// React
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
+// Navigation
+import { useNavigate } from 'react-router-dom';
+
// Redux
import { useSelector } from 'react-redux';
import { memoize } from 'proxy-memoize';
@@ -24,6 +27,9 @@ export default function SavedRoutesPage() {
/* Setup */
document.title = 'DriveBC - My Routes';
+ // Navigation
+ const navigate = useNavigate();
+
// Context
const { authContext, setAuthContext } = useContext(AuthContext);
@@ -71,6 +77,22 @@ export default function SavedRoutesPage() {
description="Manage and view your saved routes here.">
+ {authContext.loginStateKnown && authContext.username && !authContext.verified &&
+
+ {authContext.email} has not been verified. Email notifications for saved routes will be disabled until
+ verification is complete.
+
+
navigate('/verify-email')}
+ onKeyPress={() => navigate('/verify-email')}>
+
+ Verify email address
+
+
+ }
+
{authContext.loginStateKnown && authContext.username &&
{!(favRoutes && favRoutes.length) &&
diff --git a/src/frontend/src/pages/SavedRoutesPage.scss b/src/frontend/src/pages/SavedRoutesPage.scss
index 6a5efec87..c794c2d67 100644
--- a/src/frontend/src/pages/SavedRoutesPage.scss
+++ b/src/frontend/src/pages/SavedRoutesPage.scss
@@ -3,6 +3,31 @@
.saved-routes-page {
position: relative;
+ .not-verified {
+ background-color: $MyAccountWarning;
+ color: $MyAccountWarningText;
+ padding: 1rem 4rem;
+ font-size: 0.875rem;
+
+ @media (max-width: 992px) {
+ padding: 1rem 0.75rem;
+ }
+
+ .verify-link {
+ text-decoration: underline;
+ cursor: pointer;
+
+ @media (min-width: 992px) {
+ display: inline;
+ margin-left: 1rem;
+ }
+
+ @media (max-width: 992px) {
+ margin-top: 1rem;
+ }
+ }
+ }
+
.container {
@media (min-width: 576px) {
max-width: 1828px;
@@ -32,15 +57,15 @@
opacity: 1;
overflow: auto;
transition: all 0.3s ease;
-
+
@media (min-width: 576px) {
grid-template-columns: repeat(2, 1fr );
}
-
+
@media (min-width: 1240px) {
grid-template-columns: repeat(3, 1fr );
}
-
+
@media (min-width: 1480px) {
grid-template-columns: repeat(4, 1fr );
}
@@ -49,7 +74,7 @@
opacity: 0;
overflow: hidden;
}
-
+
.route-card {
border-radius: 4px;
border: none;
@@ -60,7 +85,7 @@
display: flex;
flex-direction: column;
justify-content: space-between;
-
+
@media (min-width: 576px) {
width: unset;
margin: unset;
@@ -98,7 +123,7 @@
border-top-right-radius: 0;
}
}
-
+
.route-alt-name {
margin-bottom: 0;
}
@@ -118,7 +143,7 @@
border: none;
background: none;
padding: 0;
-
+
svg {
margin-right: 8px;
}
@@ -132,7 +157,7 @@
}
}
}
-
+
.fav-cams-on-route {
background: white;
transition: all 0.3s ease;
@@ -147,13 +172,13 @@
display: flex;
justify-content: space-between;
margin-bottom: 1rem;
-
+
.close-btn {
cursor: pointer;
font-size: 20px;
margin-top: 4px;
}
-
+
.caption {
font-size: 1.125rem;
color: $Grey80;
diff --git a/src/frontend/src/pages/VerifyEmailPage.js b/src/frontend/src/pages/VerifyEmailPage.js
new file mode 100644
index 000000000..79c59654d
--- /dev/null
+++ b/src/frontend/src/pages/VerifyEmailPage.js
@@ -0,0 +1,59 @@
+// React
+import React, { useContext, useEffect } from 'react';
+
+// External imports
+import Container from 'react-bootstrap/Container';
+
+// Internal imports
+import { AuthContext } from '../App';
+import { sendVerificationEmail } from "../Components/data/user";
+import Footer from '../Footer.js';
+import PageHeader from '../PageHeader';
+
+// Styling
+import './VerifyEmailPage.scss';
+
+export default function VerifyEmailPage() {
+ const { authContext } = useContext(AuthContext);
+
+ useEffect(() => {
+ if (authContext.loginStateKnown && !authContext.verified) {
+ sendVerificationEmail();
+ }
+ }, [authContext]);
+
+ return (
+
+
+
+
+
+
+ To enable notifications your email account needs to be
+ verified. We’ve sent an email to {authContext.email} with
+ a link to verify that the account is yours.
+
+
+
+ Once you click on the link, you will be able to receive
+ notifications by email for your favourite routes.
+
+
+
+ If you can’t find the email , please check the following:
+
+ double check the spelling of your email address
+ check your junk mail folders, and add
+ add email@email.com to your whitelist
+
+
+
+ Send another verification Email
+
+
+
+
+ );
+}
diff --git a/src/frontend/src/pages/VerifyEmailPage.scss b/src/frontend/src/pages/VerifyEmailPage.scss
new file mode 100644
index 000000000..d9ef9664b
--- /dev/null
+++ b/src/frontend/src/pages/VerifyEmailPage.scss
@@ -0,0 +1,12 @@
+@import "../styles/variables.scss";
+
+.verify-email-page {
+ p {
+ font-size: 1rem;
+ margin-bottom: 1.5rem;
+ }
+
+ .instructions {
+ font-size: 1.1rem;
+ }
+}
diff --git a/src/frontend/src/styles/variables.scss b/src/frontend/src/styles/variables.scss
index f61f46052..fbd3db7c5 100644
--- a/src/frontend/src/styles/variables.scss
+++ b/src/frontend/src/styles/variables.scss
@@ -94,9 +94,14 @@ $BtnHover-Tertiary: $Grey30;
$BtnActive-Secondary: $White;
-//Animations
+//Animations
$Anim-gentle: cubic-bezier(0.175, 0.885, 0.32, 1.275);
$Border-dark: #353433;
-$GreyOnBlue: #5C6B78;
\ No newline at end of file
+$GreyOnBlue: #5C6B78;
+
+// My Account
+$MyAccountHeader: #323130;
+$MyAccountWarning: #FEF8E8;
+$MyAccountWarningText: #584215;