Skip to content

Commit

Permalink
accept invitation
Browse files Browse the repository at this point in the history
  • Loading branch information
ipula committed Jun 26, 2024
1 parent 50e3204 commit 791e8da
Show file tree
Hide file tree
Showing 15 changed files with 1,225 additions and 7 deletions.
18 changes: 11 additions & 7 deletions public/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,14 +341,14 @@ window.pkp = {
'form.saved': 'Saved',
'grid.action.sort': 'Sort',
'help.help': 'Help',
'invitation.orcid.message': '##invitation.orcid.message##',
'invitation.role.addRole.button': '##invitation.role.addRole.button##',
'invitation.role.dateEnd': '##invitation.role.dateEnd##',
'invitation.role.dateStart': '##invitation.role.dateStart##',
'invitation.role.masthead': '##invitation.role.masthead##',
'invitation.orcid.message': 'On accepting the invite, the user will redirected to ORCID to verify their account, if the wish to',
'invitation.role.addRole.button': 'Add Another Role',
'invitation.role.dateEnd': 'End Date',
'invitation.role.dateStart': 'Start Date',
'invitation.role.masthead': 'Journal Masthead',
'invitation.role.removeRole.button':
'##invitation.role.removeRole.button##',
'invitation.role.selectRole': '##invitation.role.selectRole##',
'Remove Role',
'invitation.role.selectRole': 'Select a new role',
'invitation.wizard.completeSteps': '##invitation.wizard.completeSteps##',
'issue.issue': 'Issue',
'list.collapseAll': 'Collapse all',
Expand Down Expand Up @@ -527,6 +527,10 @@ window.pkp = {
'user.orcid': 'ORCID iD',
'user.username': 'Username',
'validator.required': 'This field is required.',
'invitation.notification.closeBtn':'View all users',
'user.password': 'Password',
'invitation.orcid.acceptInvitation.message':'Not verified. You can verify your ORCID iD from your profile section in OJS',

},

tinyMCE: {
Expand Down
2 changes: 2 additions & 0 deletions src/components/Container/PageOJS.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
import Page from '@/components/Container/Page.vue';
import DashboardPage from '@/pages/dashboard/DashboardPage.vue';
import UserInvitationPage from '@/pages/userInvitation/UserInvitationPage.vue';
import AcceptInvitationPage from '@/pages/acceptInvitation/AcceptInvitationPage.vue';
export default {
components: {
DashboardPage,
UserInvitationPage,
AcceptInvitationPage,
},
extends: Page,
};
Expand Down
1 change: 1 addition & 0 deletions src/composables/useForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export function useForm(_form) {
watch(
errors,
(newErrors) => {
form.value.errors = {};
Object.keys(newErrors).forEach((key) => {
if (doesFieldExist(form.value, key)) {
form.value.errors[key] = newErrors[key];
Expand Down
95 changes: 95 additions & 0 deletions src/pages/acceptInvitation/AcceptInvitationCreateUserAccount.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<template>
<div>
<div class="userInvitation__reviewPanel__item">
<h4 class="userInvitation__reviewPanel__item__header">Email Address</h4>
<div class="userInvitation__reviewPanel__item__value">
{{ store.email }}
</div>
</div>
</div>
<br />
<field-text
:label="t('user.username')"
:value="fields.username"
name="username"
size="large"
:all-errors="sectionErrors"
@change="updateField"
/>
<br />
<field-text
:label="t('user.password')"
:value="fields.password"
name="password"
input-type="password"
size="large"
:all-errors="sectionErrors"
@change="updateField"
/>
<div>
<field-show-ensuring-link
primary-locale="en"
name="privacyStatement"
:value="fields.privacyStatement"
:all-errors="sectionErrors"
:options="options"
@change="updateField"
/>
</div>
</template>

<script setup>
import {defineProps, ref, computed} from 'vue';
import {useTranslation} from '@/composables/useTranslation';
import FieldText from '@/components/Form/fields/FieldText.vue';
import FieldShowEnsuringLink from '@/components/Form/fields/FieldShowEnsuringLink.vue';
import {useAcceptInvitationPageStore} from './AcceptInvitationPageStore';
const props = defineProps({
validateFields: {type: Array, required: true},
});
const {t} = useTranslation();
const fields = ref({username: '', password: '', privacyStatement: false});
const options = ref([
{
value: true,
label:
'Yes, I agree to have my data collected and stored according to the <button>Privacy Statement</button>.',
},
]);
const store = useAcceptInvitationPageStore();
function updateField(fieldName, b, fieldValue) {
fields.value[fieldName] = fieldValue;
store.updateAcceptInvitationPayload(fieldName, fieldValue);
}
const sectionErrors = computed(() => {
return props.validateFields.reduce((obj, key) => {
if (store.errors[key]) {
obj[key] = store.errors[key];
}
return obj;
}, {});
});
</script>
<style lang="less">
.userInvitation__reviewPanel__item {
&:last-child {
border-bottom: none;
}
}
.userInvitation__reviewPanel__item__header {
margin: 0;
font-size: 0.875rem;
line-height: 1.5rem;
}
.userInvitation__reviewPanel__item__value {
margin-bottom: 1rem;
font-size: 0.875rem;
line-height: 1.5rem;
}
div fieldset {
border: none !important;
}
</style>
74 changes: 74 additions & 0 deletions src/pages/acceptInvitation/AcceptInvitationCreateUserForms.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<template>
<div>
<div class="userInvitation__reviewPanel__item">
<h4 class="userInvitation__reviewPanel__item__header">Email Address</h4>
<div class="userInvitation__reviewPanel__item__value">
{{ store.email }}
</div>
</div>
</div>
<div>
<div class="userInvitation__reviewPanel__item">
<h4 class="userInvitation__reviewPanel__item__header">ORCID iD</h4>
<div class="userInvitation__reviewPanel__item__value">
{{
store.acceptinvitationPayload.orcid
? store.acceptinvitationPayload.orcid
: t('invitation.orcid.acceptInvitation.message')
}}
<icon
v-if="store.acceptinvitationPayload.orcid"
icon="orcid"
:inline="true"
/>
</div>
</div>
</div>
<pkp-form
v-bind="userForm"
class="userInvitation__stepForm"
@set="updateUserDetailsForm"
></pkp-form>
</template>

<script setup>
import {defineProps, computed} from 'vue';
import PkpForm from '@/components/Form/Form.vue';
import {useForm} from '@/composables/useForm';
import {useAcceptInvitationPageStore} from './AcceptInvitationPageStore';
const props = defineProps({
form: {type: Object, required: true},
validateFields: {type: Array, required: true},
});
const store = useAcceptInvitationPageStore();
function updateUserDetailsForm(a, {fields}, c, d) {
if (fields) {
fields.forEach((field) => {
if (store.acceptinvitationPayload[field.name] !== field.value) {
store.updateAcceptInvitationPayload(field.name, field.value);
}
});
}
}
const {
form: userForm,
connectWithPayload,
connectWithErrors,
} = useForm(props.form);
connectWithPayload(store.acceptinvitationPayload);
const sectionErrors = computed(() => {
return props.validateFields.reduce((obj, key) => {
if (store.errors[key]) {
obj[key] = store.errors[key];
}
return obj;
}, {});
});
connectWithErrors(sectionErrors);
</script>
17 changes: 17 additions & 0 deletions src/pages/acceptInvitation/AcceptInvitationHeader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<template>
<h1 ref="wrapper" class="app__pageHeading">
{{ pageTitle }}
</h1>
<p>
{{ pageTitleDescription }}
</p>
</template>

<script setup>
import {defineProps} from 'vue';
defineProps({
pageTitle: {type: String, required: true},
pageTitleDescription: {type: String, required: true},
});
</script>
9 changes: 9 additions & 0 deletions src/pages/acceptInvitation/AcceptInvitationPage.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {Primary, Controls, Stories, Meta, ArgTypes} from '@storybook/blocks';

import * as AcceptInvitationPage from './AcceptInvitationPage.stories.js';

<Meta of={AcceptInvitationPage} />

# User Invitation page

<ArgTypes />
70 changes: 70 additions & 0 deletions src/pages/acceptInvitation/AcceptInvitationPage.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import AcceptInvitationPage from './AcceptInvitationPage.vue';
import {http, HttpResponse} from 'msw';
import PageInitConfigMock from './mocks/pageInitConfig';
import invitationMock from './mocks/invitationMock';

export default {
title: 'Pages/AcceptInvitation',
component: AcceptInvitationPage,
};

export const Init = {
render: (args) => ({
components: {AcceptInvitationPage},
setup() {
return {args};
},
template: '<AcceptInvitationPage v-bind="args" />',
}),
parameters: {
msw: {
handlers: [
http.get(
'https://mock/index.php/publicknowledge/api/v1/invitations/65/key/8aqc3W',
async (r) => {
return HttpResponse.json(invitationMock, {status: 200});
},
),
http.post(
'https://mock/index.php/publicknowledge/api/v1/invitations/65/key/8aqc3W/refine',
async ({request}) => {
const postBody = await request.json();
let errors = {};

if (!Object.keys(postBody).includes('username')) {
errors['username'] = ['This field is required'];
}
if (!Object.keys(postBody).includes('password')) {
errors['password'] = ['This field is required'];
}
if (!Object.keys(postBody).includes('affiliation')) {
errors['affiliation'] = ['This field is required'];
}
if (!Object.keys(postBody).includes('country')) {
errors['country'] = ['This field is required'];
}
Object.keys(postBody).forEach((element) => {
if (element !== 'orcid') {
if (postBody[element] === '') {
errors[element] = ['This field is required'];
}
}
});

if (Object.keys(errors).length > 0) {
return HttpResponse.json(errors, {status: 422});
}
return HttpResponse.json(postBody, {status: 200});
},
),
http.post(
'https://mock/index.php/publicknowledge/api/v1/invitations/65/key/8aqc3W/finalize',
async (r) => {
return HttpResponse.json(invitationMock, {status: 201});
},
),
],
},
},
args: PageInitConfigMock,
};
Loading

0 comments on commit 791e8da

Please sign in to comment.