From befb7efa65d77191541ea22f89d537347e2e9d3b Mon Sep 17 00:00:00 2001 From: ipula Date: Fri, 2 Feb 2024 18:37:28 +0100 Subject: [PATCH] create user --- src/components/Container/PageOJS.vue | 2 + src/pages/createUser/CreateUserAccount.vue | 17 + src/pages/createUser/CreateUserForms.vue | 19 + src/pages/createUser/CreateUserHeader.vue | 17 + .../createUser/CreateUserInvitedRoles.vue | 34 ++ src/pages/createUser/CreateUserPage.vue | 399 ++++++++++++++++++ src/pages/createUser/CreateUserPageStore.js | 348 +++++++++++++++ src/pages/createUser/CreateUserReview.vue | 30 ++ .../createUser/CreateUserVerifyOrcid.vue | 9 + 9 files changed, 875 insertions(+) create mode 100644 src/pages/createUser/CreateUserAccount.vue create mode 100644 src/pages/createUser/CreateUserForms.vue create mode 100644 src/pages/createUser/CreateUserHeader.vue create mode 100644 src/pages/createUser/CreateUserInvitedRoles.vue create mode 100644 src/pages/createUser/CreateUserPage.vue create mode 100644 src/pages/createUser/CreateUserPageStore.js create mode 100644 src/pages/createUser/CreateUserReview.vue create mode 100644 src/pages/createUser/CreateUserVerifyOrcid.vue diff --git a/src/components/Container/PageOJS.vue b/src/components/Container/PageOJS.vue index dd798b54e..574e058ff 100644 --- a/src/components/Container/PageOJS.vue +++ b/src/components/Container/PageOJS.vue @@ -2,11 +2,13 @@ import Page from '@/components/Container/Page.vue'; import SubmissionsPage from '@/pages/submissions/SubmissionsPage.vue'; import UserInvitationPage from '@/pages/userInvitation/UserInvitationPage.vue'; +import CreateUserPage from '@/pages/createUser/CreateUserPage.vue'; export default { components: { SubmissionsPage, UserInvitationPage, + CreateUserPage, }, extends: Page, }; diff --git a/src/pages/createUser/CreateUserAccount.vue b/src/pages/createUser/CreateUserAccount.vue new file mode 100644 index 000000000..74554a9ec --- /dev/null +++ b/src/pages/createUser/CreateUserAccount.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/pages/createUser/CreateUserForms.vue b/src/pages/createUser/CreateUserForms.vue new file mode 100644 index 000000000..4baad65b1 --- /dev/null +++ b/src/pages/createUser/CreateUserForms.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/pages/createUser/CreateUserHeader.vue b/src/pages/createUser/CreateUserHeader.vue new file mode 100644 index 000000000..f67629358 --- /dev/null +++ b/src/pages/createUser/CreateUserHeader.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/pages/createUser/CreateUserInvitedRoles.vue b/src/pages/createUser/CreateUserInvitedRoles.vue new file mode 100644 index 000000000..a0cd95eae --- /dev/null +++ b/src/pages/createUser/CreateUserInvitedRoles.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/pages/createUser/CreateUserPage.vue b/src/pages/createUser/CreateUserPage.vue new file mode 100644 index 000000000..fb002d7b7 --- /dev/null +++ b/src/pages/createUser/CreateUserPage.vue @@ -0,0 +1,399 @@ + + + + + diff --git a/src/pages/createUser/CreateUserPageStore.js b/src/pages/createUser/CreateUserPageStore.js new file mode 100644 index 000000000..591b159b7 --- /dev/null +++ b/src/pages/createUser/CreateUserPageStore.js @@ -0,0 +1,348 @@ +import {useTranslation} from '@/composables/useTranslation'; + +import {defineComponentStore} from '@/utils/defineComponentStore'; +// import {useFetch} from '@/composables/useFetch'; +import {computed, onMounted, ref, watch} from 'vue'; +//let pageInitConfig = null; + +/*export function initSubmissionsPageStore(_pageInitConfig) { + pageInitConfig = _pageInitConfig; +} + +export function disposeSubmissionsPageStore() { + const store = useSubmissionsPageStore(); + store.$dispose(); + pageInitConfig = null; + delete getActivePinia().state.value[store.$id]; +}*/ + +export const useCreateUserPageStore = defineComponentStore( + 'userInvitationPage', + (pageInitConfig) => { + /** + * Translation + */ + + const {t} = useTranslation(); + + const currentStepId = ref(pageInitConfig.steps[0].id); + const steps = ref(pageInitConfig.steps); + const pageTitleDescription = ref(pageInitConfig.pageTitleDescription); + const errors = ref({}); + const startedSteps = ref([]); + const isModalOpened = ref(false); + + const usernameField = ref({ + label: t('user.username'), + name: 'username', + size: 'large', + value: '', + }); + const passwordField = ref({ + label: t('user.password'), + name: 'password', + size: 'large', + value: '', + inputType: 'password', + }); + const password = ref(''); + const username = ref(''); + /** + * The currently active step + */ + const currentStep = computed(() => { + return steps.value.find((step) => step.id === currentStepId.value); + }); + + /** + * The index of the currently active step + * in the steps array + */ + const currentStepIndex = computed(() => { + return steps.value.findIndex((step) => step.id === currentStepId.value); + }); + + /** + * Is the current step the first step? + */ + const isOnFirstStep = computed(() => { + return !currentStepIndex.value; + }); + + /** + * Is the current step the last step? + */ + const isOnLastStep = computed(() => { + return currentStepIndex.value === steps.value.length - 1; + }); + + /** + * Are there any validation errors? + */ + const isValid = computed(() => { + return Object.keys(errors.value).length === 0; + }); + /** + * The title to show at the top of the page + */ + const pageTitle = computed(() => { + if (!currentStep.value) { + return ''; + } + return currentStep.value.name.replace('{$step}', currentStep.value); + }); + + /** + * The step title to show at the top of the step + */ + const stepTitle = computed(() => { + if (!currentStep.value) { + return ''; + } + return currentStep.value.reviewName.replace( + '{$step}', + 'STEP ' + (1 + currentStepIndex.value), + ); + }); + + /** + * Update when the step changes + */ + watch(currentStepIndex, async (newVal, oldVal) => { + if (newVal === oldVal) { + return; + } + + // Update the list of steps that have been started + steps.value.forEach((step, i) => { + if ( + !startedSteps.value.includes(step.id) && + i <= currentStepIndex.value + ) { + startedSteps.value.push(step.id); + } + }); + + // Track step changes in the title and browser history + const step = steps.value[newVal]; + // document.title = this.getPageTitle(step); + if (step.id !== window.location.hash.replace('#', '')) { + addHistory(step); + } + + // Trigger validation on the review step + if (newVal === steps.value.length - 1) { + validate(); + } + }); + + /** + * Set form data when validation errors are changed + */ + watch(errors, async (newVal, oldVal) => { + const keys = Object.keys(newVal); + steps.value.forEach((step, stepIndex) => { + step.sections.forEach((section, sectionIndex) => { + if (section.type === 'form') { + section.form.fields.forEach((field) => { + if (keys.includes(field.name)) { + steps.value[stepIndex].sections[sectionIndex].form.errors = { + ...steps.value[stepIndex].sections[sectionIndex].form.errors, + ...{[field.name]: newVal[field.name]}, + }; + } + }); + } + }); + }); + }); + + onMounted(() => { + /** + * Open the correct step when the page is loaded + */ + if (!window.location.hash) { + openStep(steps.value[0].id); + } + }); + + function passwordChange(fieldName, propName, newValue, localeKey) { + password.value = newValue; + } + function usernameChange(fieldName, propName, newValue, localeKey) { + username.value = newValue; + } + /** + * Add a step change to the browser history so the + * user can use the browser's back button + * + * @param {Object} step The step to add + */ + function addHistory(step) { + window.history.pushState({}, step.name, '#' + step.id); + } + + /** + * Go to the next step or submit if this is the last step + */ + function nextStep() { + if (isOnLastStep.value) { + submit(); + } else { + openStep(steps.value[1 + currentStepIndex.value].id); + } + } + + /** + * Go to a step in the wizard + * + * @param {String} stepId + */ + function openStep(stepId) { + const newStep = steps.value.find((step) => step.id === stepId); + if (!newStep) { + return; + } + if (stepId === 'userInvitedEmail') { + errors.value = {}; + } + currentStepId.value = stepId; + } + + /** + * Go to the previous step in the wizard + */ + function previousStep() { + const previousIndex = currentStepIndex.value - 1; + if (previousIndex >= 0) { + openStep(steps.value[previousIndex].id); + } + } + + /** + * Validate the user details + * + * Always wait for autosaves to complete before + * trying to validate + */ + function validate() {} + + /** + * Update an autosave form + * + * @param {String} formId + * @param {Object} data + */ + function updateAutosaveForm(formId, data) { + updateForm(formId, data); + } + + /** + * Complete the submission + * + * Opens a confirmation dialog and then makes the submission + * request with any required confirmation fields + */ + async function submit() {} + + /** + * Update a form with new data + * + * This is fired every time a form field changes, so + * resource-intensive code should not be run every + * time this method is called. + * + * @param {String} formId + * @param {Object} data + */ + function updateForm(formId, data) { + steps.value.forEach((step, stepIndex) => { + step.sections.forEach((section, sectionIndex) => { + if (section.type !== 'form' || section.form.id !== formId) { + return; + } + steps.value[stepIndex].sections[sectionIndex].form = { + ...steps.value[stepIndex].sections[sectionIndex].form, + ...data, + }; + steps.value[stepIndex].sections[sectionIndex].form.fields.forEach( + (field) => { + if (data[field.name] instanceof Object) { + field.value = data[field.name][pageInitConfig.primaryLocale]; + } else { + field.value = data[field.name]; + } + }, + ); + }); + }); + } + /** + * Complete the submission + * + * Opens a confirmation dialog and then makes the submission + * request with any required confirmation fields + */ + // async function searchUser() { + // } + + /** + * Update the data attached to a step + * + * @param {String} stepId The id of the step to update + * @param {Object} data The data to update in the step + */ + function updateStep(stepId, data) { + steps.value.forEach((step, stepIndex) => { + step.sections.forEach((section, sectionIndex) => { + if (section.type !== 'email') { + return; + } + let errors = {...step.sections.errors}; + Object.keys(data).forEach((key) => delete errors[key]); + steps.value[stepIndex].sections[sectionIndex].email = { + ...steps.value[stepIndex].sections[sectionIndex].email, + ...data, + errors: errors, + }; + }); + }); + } + + function isModalClosed(params) { + isModalOpened.value = false; + } + + return { + //computed + currentStep, + currentStepIndex, + isOnFirstStep, + isOnLastStep, + isValid, + pageTitle, + startedSteps, + stepTitle, + openStep, + steps, + pageTitleDescription, + errors, + + //form feilds + passwordField, + usernameField, + passwordChange, + usernameChange, + + //methods + nextStep, + previousStep, + updateStep, + updateAutosaveForm, + + //modal + isModalOpened, + isModalClosed, + }; + }, +); diff --git a/src/pages/createUser/CreateUserReview.vue b/src/pages/createUser/CreateUserReview.vue new file mode 100644 index 000000000..44e8cc35e --- /dev/null +++ b/src/pages/createUser/CreateUserReview.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/pages/createUser/CreateUserVerifyOrcid.vue b/src/pages/createUser/CreateUserVerifyOrcid.vue new file mode 100644 index 000000000..d70628fd6 --- /dev/null +++ b/src/pages/createUser/CreateUserVerifyOrcid.vue @@ -0,0 +1,9 @@ + + +