Skip to content

Commit

Permalink
DBC22-2869: FE integration in saved route and account pages
Browse files Browse the repository at this point in the history
  • Loading branch information
ray-oxd authored and minORC committed Jan 6, 2025
1 parent c960cb7 commit 8a9bcf5
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 16 deletions.
3 changes: 2 additions & 1 deletion src/backend/apps/authentication/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/backend/apps/shared/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions src/frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
});
})
Expand Down Expand Up @@ -199,6 +202,7 @@ function App() {
<Route path="/bulletins" element={<BulletinsListPage />} />
<Route path="/bulletins/:id" element={<BulletinDetailsPage />} />
<Route path="/account" element={<AccountPage />} />
<Route path="/verify-email" element={<VerifyEmailPage />} />
{/* Catch-all route for 404 errors */}
<Route path="*" element={<NotFoundPage />} />
<Route path="/problems" element={<ProblemsPage />} />
Expand Down
14 changes: 12 additions & 2 deletions src/frontend/src/pages/AccountPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -33,7 +32,18 @@ export default function AccountPage() {
</PageHeader>

<Container>
<button onClick={sendVerificationEmail}>Send Verification Email</button>
<div className='email-address'>
<p className='header'>Email Address</p>
<p className='email'>{authContext.email}</p>

{!authContext.verified &&
<p className='not-verified'>
This email address has not been verified. Email notifications for
saved routes will be disabled until verification
is complete.
</p>
}
</div>
</Container>

<Footer/>
Expand Down
21 changes: 21 additions & 0 deletions src/frontend/src/pages/AccountPage.scss
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
22 changes: 22 additions & 0 deletions src/frontend/src/pages/SavedRoutesPage.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -24,6 +27,9 @@ export default function SavedRoutesPage() {
/* Setup */
document.title = 'DriveBC - My Routes';

// Navigation
const navigate = useNavigate();

// Context
const { authContext, setAuthContext } = useContext(AuthContext);

Expand Down Expand Up @@ -71,6 +77,22 @@ export default function SavedRoutesPage() {
description="Manage and view your saved routes here.">
</PageHeader>

{authContext.loginStateKnown && authContext.username && !authContext.verified &&
<div className='not-verified'>
{authContext.email} has not been verified. Email notifications for saved routes will be disabled until
verification is complete.

<div
className='verify-link'
tabIndex={0}
onClick={() => navigate('/verify-email')}
onKeyPress={() => navigate('/verify-email')}>

<b>Verify email address</b>
</div>
</div>
}

{authContext.loginStateKnown && authContext.username &&
<Container className="content-container">
{!(favRoutes && favRoutes.length) &&
Expand Down
45 changes: 35 additions & 10 deletions src/frontend/src/pages/SavedRoutesPage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 );
}
Expand All @@ -49,7 +74,7 @@
opacity: 0;
overflow: hidden;
}

.route-card {
border-radius: 4px;
border: none;
Expand All @@ -60,7 +85,7 @@
display: flex;
flex-direction: column;
justify-content: space-between;

@media (min-width: 576px) {
width: unset;
margin: unset;
Expand Down Expand Up @@ -98,7 +123,7 @@
border-top-right-radius: 0;
}
}

.route-alt-name {
margin-bottom: 0;
}
Expand All @@ -118,7 +143,7 @@
border: none;
background: none;
padding: 0;

svg {
margin-right: 8px;
}
Expand All @@ -132,7 +157,7 @@
}
}
}

.fav-cams-on-route {
background: white;
transition: all 0.3s ease;
Expand All @@ -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;
Expand Down
59 changes: 59 additions & 0 deletions src/frontend/src/pages/VerifyEmailPage.js
Original file line number Diff line number Diff line change
@@ -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 (
<div className="verify-email-page">
<PageHeader
title="Please verify your email"
description="">
</PageHeader>

<Container>
<p className='base-instructions'>
To enable notifications your email account needs to be
verified. We’ve sent an email to <b>{authContext.email}</b> with
a link to verify that the account is yours.
</p>

<p>
Once you click on the link, you will be able to receive
notifications by email for your favourite routes.
</p>

<p>
<b>If you can’t find the email</b>, please check the following:
<ul>
<li>double check the spelling of your email address</li>
<li>check your junk mail folders, and add</li>
<li>add [email protected] to your whitelist</li>
</ul>
</p>

<button className='btn btn-outline-primary' onClick={sendVerificationEmail} onKeyPress={sendVerificationEmail}>Send another verification Email</button>
</Container>

<Footer/>
</div>
);
}
12 changes: 12 additions & 0 deletions src/frontend/src/pages/VerifyEmailPage.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@import "../styles/variables.scss";

.verify-email-page {
p {
font-size: 1rem;
margin-bottom: 1.5rem;
}

.instructions {
font-size: 1.1rem;
}
}
9 changes: 7 additions & 2 deletions src/frontend/src/styles/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
$GreyOnBlue: #5C6B78;

// My Account
$MyAccountHeader: #323130;
$MyAccountWarning: #FEF8E8;
$MyAccountWarningText: #584215;

0 comments on commit 8a9bcf5

Please sign in to comment.