Skip to content

Commit

Permalink
Merge pull request #211 from Police-Data-Accessibility-Project/refact…
Browse files Browse the repository at this point in the history
…or/miscellaneous-updates-to-signin

refactor: miscellaneous updates to signin
  • Loading branch information
mbodeantor committed Mar 20, 2024
2 parents 632a1ec + 361fffb commit 8ba68b8
Show file tree
Hide file tree
Showing 13 changed files with 141 additions and 61 deletions.
8 changes: 6 additions & 2 deletions client/src/App.vue
@@ -1,14 +1,17 @@
<template>
<AuthWrapper>
<Header :logo-image-src="lockup" />
<router-view />
<ErrorBoundary component="main">
<router-view />
</ErrorBoundary>
<Footer :logo-image-src="acronym" />
</AuthWrapper>
</template>

<script>
import { Footer, Header } from 'pdap-design-system';
import AuthWrapper from './components/AuthWrapper.vue';
import ErrorBoundary from './components/ErrorBoundary.vue';
import acronym from 'pdap-design-system/images/acronym.svg';
import lockup from 'pdap-design-system/images/lockup.svg';
Expand All @@ -18,6 +21,7 @@ export default {
name: 'App',
components: {
AuthWrapper,
ErrorBoundary,
Header,
Footer,
},
Expand All @@ -40,6 +44,6 @@ export default {
}
main {
min-height: calc(100% - 80px - 500px);
min-height: calc(100vh - 80px - 500px);
}
</style>
37 changes: 37 additions & 0 deletions client/src/components/ErrorBoundary.vue
@@ -0,0 +1,37 @@
<template>
<component
:is="component"
v-if="error"
class="pdap-flex-container-center h-[full]"
>
<h1>Oops, something went wrong!</h1>
<p class="max-w-full" data-test="error-boundary-message">
If you keep seeing this message, please email
<a href="mailto:contact@pdap.io">contact@pdap.io</a> for assistance.
</p>
</component>
<slot v-else />
</template>
<script>
export default {
props: {
component: {
type: String,
default: 'div',
},
},
data() {
return {
error: false,
};
},
errorCaptured(error) {
this.interceptError(error);
},
methods: {
interceptError(error) {
this.error = error;
},
},
};
</script>
@@ -0,0 +1,10 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`ErrorBoundary > renders error content with error 1`] = `
<div class="pdap-flex-container-center h-[full]">
<h1>Oops, something went wrong!</h1>
<p class="max-w-full"> If you keep seeing this message, please email <a href="mailto:contact@pdap.io">contact@pdap.io</a> for assistance. </p>
</div>
`;

exports[`ErrorBoundary > renders slot content with no error 1`] = `<div></div>`;
1 change: 0 additions & 1 deletion client/src/components/__tests__/authWrapper.test.js
Expand Up @@ -14,7 +14,6 @@ const NOW_PLUS_THIRTY = NOW + 30 * 1000;
describe('AuthWrapper', () => {
beforeEach(() => {
wrapper = mount(AuthWrapper, {
// props: { dataSource },
global: {
plugins: [createTestingPinia()],
},
Expand Down
31 changes: 31 additions & 0 deletions client/src/components/__tests__/errorBoundary.test.js
@@ -0,0 +1,31 @@
import { mount } from '@vue/test-utils';
import { beforeEach, describe, expect, it } from 'vitest';
import ErrorBoundary from '../ErrorBoundary.vue';
import { nextTick } from 'vue';

let wrapper;

describe('ErrorBoundary', () => {
beforeEach(() => {
wrapper = mount(ErrorBoundary, {
slots: {
default: '<div data-test="default-slot" />',
},
});
});

it('renders slot content with no error', () => {
expect(wrapper.find('[data-test="default-slot"]').exists()).toBe(true);
expect(wrapper.html()).toMatchSnapshot();
});

it('renders error content with error', async () => {
wrapper.vm.interceptError(new Error('Generic error'));
await nextTick();

expect(wrapper.find('[data-test="error-boundary-message"]').exists()).toBe(
true,
);
expect(wrapper.html()).toMatchSnapshot();
});
});
2 changes: 1 addition & 1 deletion client/src/pages/LogIn.vue
Expand Up @@ -208,7 +208,7 @@ async function onSubmit(formValues) {
success.value = SUCCESS_COPY[type.value];
} catch (err) {
error.value = err.message;
error.value = 'Something went wrong, please try again.';
} finally {
loading.value = false;
}
Expand Down
15 changes: 15 additions & 0 deletions client/src/pages/NotFound.vue
@@ -0,0 +1,15 @@
<template>
<main class="p-4">
<h1>Something went wrong on our end</h1>
<p>
If you keep seeing this message, please email
<a href="mailto:contact@pdap.io">contact@pdap.io</a> for assistance.
</p>
</main>
</template>

<script>
export default {
name: 'NotFound',
};
</script>
2 changes: 1 addition & 1 deletion client/src/pages/ResetPassword.vue
Expand Up @@ -18,7 +18,7 @@
<p
v-if="isExpiredToken"
data-test="token-expired"
class="flex flex-col items-start sm:flex-row sm:items-center sm:gap-4"
class="flex flex-col items-start sm:gap-4"
>
Sorry, that token has expired.
<RouterLink
Expand Down
14 changes: 8 additions & 6 deletions client/src/pages/SearchResultPage.vue
Expand Up @@ -55,12 +55,12 @@
{{ section.header }}
</GridItem>

<SearchResultCard
v-for="record in section.records"
:key="record.type"
data-test="search-results-cards"
:data-source="searchResult[record.type]"
/>
<ErrorBoundary v-for="record in section.records" :key="record.type">
<SearchResultCard
data-test="search-results-cards"
:data-source="searchResult[record.type]"
/>
</ErrorBoundary>
</GridContainer>
</div>
</main>
Expand All @@ -69,6 +69,7 @@
<script>
import { Button, GridContainer, GridItem } from 'pdap-design-system';
import SearchResultCard from '../components/SearchResultCard.vue';
import ErrorBoundary from '../components/ErrorBoundary.vue';
import axios from 'axios';
import pluralize from '../util/pluralize';
import { SEARCH_RESULTS_UI_SHAPE } from '../util/pageData';
Expand All @@ -77,6 +78,7 @@ export default {
name: 'SearchResultPage',
components: {
Button,
ErrorBoundary,
SearchResultCard,
GridContainer,
GridItem,
Expand Down
2 changes: 1 addition & 1 deletion client/src/pages/__tests__/login.test.js
Expand Up @@ -96,7 +96,7 @@ describe('Login page', () => {

const error = form.find('.pdap-form-error-message');
expect(error.exists()).toBe(true);
expect(error.text()).toBe('foo');
expect(error.text()).toBe('Something went wrong, please try again.');
});
});

Expand Down
8 changes: 5 additions & 3 deletions client/src/router.js
Expand Up @@ -2,11 +2,12 @@ import { createWebHistory, createRouter } from 'vue-router';
import { useAuthStore } from './stores/auth';

import ChangePassword from './pages/ChangePassword.vue';
import DataSourceStaticView from '../src/pages/DataSourceStaticView.vue';
import DataSourceStaticView from './pages/DataSourceStaticView.vue';
import LogIn from './pages/LogIn.vue';
import QuickSearchPage from '../src/pages/QuickSearchPage.vue';
import QuickSearchPage from './pages/QuickSearchPage.vue';
import ResetPassword from './pages/ResetPassword.vue';
import SearchResultPage from '../src/pages/SearchResultPage.vue';
import SearchResultPage from './pages/SearchResultPage.vue';
import NotFound from './pages/NotFound.vue';

export const PRIVATE_ROUTES = ['/change-password'];

Expand Down Expand Up @@ -37,6 +38,7 @@ const routes = [
component: ResetPassword,
name: 'ResetPassword',
},
{ path: '/:pathMatch(.*)*', name: 'not-found', component: NotFound },
];

const router = createRouter({
Expand Down
22 changes: 9 additions & 13 deletions client/src/stores/auth.js
Expand Up @@ -24,21 +24,17 @@ export const useAuthStore = defineStore('auth', {
async login(email, password) {
const user = useUserStore();

try {
const response = await axios.post(
LOGIN_URL,
{ email, password },
HEADERS,
);
const response = await axios.post(
LOGIN_URL,
{ email, password },
HEADERS,
);

// Update user store with email
user.$patch({ email });
// Update user store with email
user.$patch({ email });

this.parseTokenAndSetData(response);
if (this.returnUrl) router.push(this.returnUrl);
} catch (error) {
throw new Error(error.response?.data?.message);
}
this.parseTokenAndSetData(response);
if (this.returnUrl) router.push(this.returnUrl);
},

logout(isAuthRoute) {
Expand Down
50 changes: 17 additions & 33 deletions client/src/stores/user.js
Expand Up @@ -19,50 +19,34 @@ export const useUserStore = defineStore('user', {
async signup(email, password) {
const auth = useAuthStore();

try {
await axios.post(SIGNUP_URL, { email, password }, HEADERS);
// Update store with email
this.$patch({ email });
// Log users in after signup and return that response
return await auth.login(email, password);
} catch (error) {
throw new Error(error.response?.data?.message);
}
await axios.post(SIGNUP_URL, { email, password }, HEADERS);
// Update store with email
this.$patch({ email });
// Log users in after signup and return that response
return await auth.login(email, password);
},

async changePassword(email, password) {
const auth = useAuthStore();
try {
await axios.put(
CHANGE_PASSWORD_URL,
{ email, password },
{
headers: {
...HEADERS.headers,
Authorization: `Bearer ${auth.accessToken.value}`,
},
await axios.put(
CHANGE_PASSWORD_URL,
{ email, password },
{
headers: {
...HEADERS.headers,
Authorization: `Bearer ${auth.accessToken.value}`,
},
);
return await auth.login(email, password);
} catch (error) {
throw new Error(error.response?.data?.message);
}
},
);
return await auth.login(email, password);
},

async requestPasswordReset(email) {
try {
await axios.post(REQUEST_PASSWORD_RESET_URL, { email }, HEADERS);
} catch (error) {
throw new Error(error.response?.data?.message);
}
await axios.post(REQUEST_PASSWORD_RESET_URL, { email }, HEADERS);
},

async resetPassword(password, token) {
try {
await axios.post(`${PASSWORD_RESET_URL}`, { password, token }, HEADERS);
} catch (error) {
throw new Error(error.response?.data?.message);
}
await axios.post(`${PASSWORD_RESET_URL}`, { password, token }, HEADERS);
},
},
});

0 comments on commit 8ba68b8

Please sign in to comment.