Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task-Upgrade composition api #9

Open
wants to merge 18 commits into
base: upgrade-vue3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3763750
Feature: Creates interfaces for callable methods of global components
Ovsdrak Mar 8, 2023
3e3bba6
Feature: Provides AlertMessage and Loader to the Global API
Ovsdrak Mar 8, 2023
e9c606d
Refactor: Updates Login component with Composition API structure
Ovsdrak Mar 8, 2023
c7e6aef
Refactor: Updates GeneralData component with Composition API structure
Ovsdrak Mar 8, 2023
9728f33
Refactor: Updates UpdatePassword.ts component with Composition API st…
Ovsdrak Mar 8, 2023
034ae3e
Refactor: Updates ForgotPassword.vue component with Composition API s…
Ovsdrak Mar 8, 2023
ef8ebc8
Refactor: Updates ModalRemove.vue component with Composition API stru…
Ovsdrak Mar 8, 2023
cbffbbf
Refactor: Updates NavigationDrawer.vue component with Composition API…
Ovsdrak Mar 8, 2023
5e5410c
Refactor: Updates ListUsers.vue component with Composition API structure
Ovsdrak Mar 9, 2023
d6cfe70
Refactor: Updates ListProfiles.vue component with Composition API str…
Ovsdrak Mar 9, 2023
84abc7a
Refactor: Updates SaveUser.vue component with Composition API structure
Ovsdrak Mar 9, 2023
b0075dd
Refactor: Updates SaveProfile.vue component with Composition API stru…
Ovsdrak Mar 9, 2023
5e34288
Docs: Updates copyright
Ovsdrak Mar 9, 2023
f74ea2b
Refactor: Updates UserLogged.vue component with the composition API.
Ovsdrak Mar 9, 2023
5f10cc8
Refactor: Updates ResetPassword.vue component with the composition API.
Ovsdrak Mar 9, 2023
e85c55e
Refactor: Updates SetInitialPassword.vue component with the compositi…
Ovsdrak Mar 9, 2023
6b3d65c
Fix: Fixes bugs related to type safety
Ovsdrak Mar 9, 2023
89409ef
Refactor: Organizes SaveProfile.vue by features
Ovsdrak Mar 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion imports/api/Users/UsersCtrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,14 @@ export const updatePersonalDataMethod = new ValidatedMethod({
validate({ user }: { user: Meteor.User }) {
try {
check(user, {
_id: String,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not necessary since we can take the user id from the current connection

username: String,
emails: [{ address: String, verified: Boolean }],
profile: {
profile: String,
name: String,
path: Match.Maybe(String)
path: Match.Maybe(String),
updated_at: String
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use camel case, please?

}
});
} catch (exception) {
Expand Down
24 changes: 21 additions & 3 deletions imports/ui/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,38 @@
<component :is="Component"/>
</transition>
</router-view>
<alert-message/>
<loader/>
<alert-message ref="alertMessage"/>
<loader ref="loader"/>
</v-app>
</template>

<script lang="ts">
import AlertMessage from '@components/Utilities/Alerts/AlertMessage.vue';
import Loader from '@components/Utilities/Loaders/Loader.vue';
import { defineComponent } from 'vue';
import { defineComponent, onMounted, provide, ref } from 'vue';
import { Injections } from '@typings/utilities';
import mitt from 'mitt';

export default defineComponent({
name: 'App',
components: { AlertMessage, Loader },
setup() {
const alertMessage = ref(null);
const loader = ref(null);

onMounted(() => {
provide(Injections.AlertMessage, alertMessage.value);
provide(Injections.Loader, loader.value);
const emitter = mitt();
provide(Injections.Emitter, emitter);
})
Comment on lines +27 to +32
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this for?

if it is to use those components in the global scope, I had implemented in their mounted hooks the code to make them globals. Besides, I added mitt in the imports/startup/client/index.ts file to configure the event emitter as global.


return { alertMessage, loader };
}
});



</script>

<style>
Expand Down
109 changes: 54 additions & 55 deletions imports/ui/components/ConfigureAccount/GeneralData.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,77 +64,76 @@

<script lang="ts">
import profilesMixin from '@mixins/accounts/profiles';
import validateForm from '@mixins/validateForm';
import uploadImage from '@mixins/users/uploadImage';
import { Form, Field, FormContext } from 'vee-validate';
import { Meteor } from 'meteor/meteor';
import { User } from '@typings/users';
import { defineComponent } from 'vue';
import { defineComponent, inject, reactive, ref } from 'vue';
import { ResponseMessage } from '@server/utils/ResponseMessage';
import { useAuthStore } from '/imports/ui/stores/auth';
import { useFormValidation } from '/imports/ui/composables/forms';
import { Injections, MeteorError } from '@typings/utilities';
import { AlertMessageType } from '@components/Utilities/Alerts/AlertMessage.vue';
import { LoaderType } from '@components/Utilities/Loaders/Loader.vue';
import { useUploadImage } from '/imports/ui/composables/users/uploadImage';
import { Emitter, EventType } from 'mitt';

export default defineComponent({
name: 'GeneralData',
mixins: [validateForm, profilesMixin, uploadImage],
mixins: [profilesMixin],
components: {
Form,
Field
},
setup() {
setup: function () {
const authStore = useAuthStore();
return { authStore };
},
data() {
return {
user: {
emails: [{ verified: false }],
profile: {}
} as User,
photoFileUser: null,
initialValues: {
name: '',
username: '',
email: ''
}
};
},
created() {
const user = this.authStore.user;
if (user) {
this.user = {
username: user.username,
emails: user.emails,
profile: {
profile: user.profile.profile,
name: user.profile.name,
path: user.profile.path
}
};
this.initialValues = {
name: user.profile.name as string,
username: user.username as string,
email: user.emails[0].address as string
};
}
},
methods: {
async saveUser() {
if (await this.isFormValid(this.$refs.dataFormObserver as FormContext)) {
this.$loader.activate('Updating data. . .');
Meteor.call('user.updatePersonalData', { user: this.user, photoFileUser: this.photoFileUser },
(err: Meteor.Error, response: ResponseMessage) => {
this.$loader.deactivate();
if (err) {
console.error('Error to save user: ', err);
this.$alert.showAlertSimple('error', err.reason);
const dataFormObserver = ref<FormContext | null>(null);
const alert = inject<AlertMessageType>(Injections.AlertMessage);
const loader = inject<LoaderType>(Injections.Loader);
Comment on lines +90 to +91
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if we can access with global props as shown:

this.$alert
this.$loader

const emitter = inject<Emitter<Record<EventType, unknown>>>(Injections.Emitter);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if we can use this.emitter instead

const user: User = reactive(authStore.user ? {...authStore.user} : {
emails: [{verified: false}],
profile: {}
});
const initialValues = reactive({
name: authStore.user?.profile.name || '',
username: authStore.user?.username || '',
email: authStore.user?.emails[0].address || ''
})
const photoFileUser = ref(null);
const {file, onClickUploadButton} = useUploadImage('fileUpload', (ev) => {
user.profile.path = ev.target.result;
photoFileUser.value = ev.target.result;
})

const saveUser = async () => {
const observer = dataFormObserver.value as FormContext | null;
if (observer && alert && await useFormValidation(observer, alert)) {
loader?.activate('Updating data . . .');
Meteor.call('user.updatePersonalData', {user, photoFileUser: photoFileUser.value},
(error: MeteorError, response: ResponseMessage) => {
loader?.deactivate();
if (error && error instanceof Meteor.Error) {
console.error('Error to save user: ', error);
alert?.showAlertSimple('error', error.reason + '');
} else {
this.authStore.setUser(Meteor.user());
this.emitter.emit('setUserLogged');
this.$alert.showAlertSimple('success', response.message);
authStore.setUser(Meteor.user() as User);
emitter?.emit('setUserLogged');
alert?.showAlertSimple('success', response.message + '');
}
});
})
}
}
};

return {
authStore,
dataFormObserver,
saveUser,
initialValues,
photoFileUser,
user,
file,
onClickUploadButton
};
}
});
</script>
71 changes: 36 additions & 35 deletions imports/ui/components/ConfigureAccount/UpdatePassword.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@
import JsonHelper from '@mixins/helpers/json';
import validateForm from '@mixins/validateForm';
import { Form, Field, FormContext } from 'vee-validate';
import { defineComponent } from 'vue';
import { Meteor } from 'meteor/meteor';
import { defineComponent, inject, reactive, ref } from 'vue';
import { AlertMessageType } from '@components/Utilities/Alerts/AlertMessage.vue';
import { Injections, MeteorError } from '@typings/utilities';
import { useFormValidation } from '/imports/ui/composables/forms';
import { useNullifyObject } from '/imports/ui/composables/helpers/json';

interface PasswordInput {
old: string | null;
Expand All @@ -73,41 +76,39 @@ export default defineComponent({
Field
},
mixins: [validateForm, JsonHelper],
data() {
return {
password: {
old: null,
new: null,
confirm: null
} as PasswordInput,
showPass: {
old: false,
new: false,
confirm: false
setup() {
const passwordFormObserver = ref(null);
const alert = inject<AlertMessageType>(Injections.AlertMessage);
const password: PasswordInput = reactive({
old: null,
new: null,
confirm: null
});
const showPass = reactive({
old: false,
new: false,
confirm: false
});

const updatePassword = async () => {
const observer = passwordFormObserver.value as FormContext | null;
if (observer && alert && await useFormValidation(observer, alert)) {
Accounts.changePassword(password.old || '', password.new || '',
async (error: MeteorError) => {
useNullifyObject(password);
observer.resetForm();
if (error) {
console.error('Error changing password: ', error);
alert?.showAlertSimple('error', 'An error occurred while changing the password.');
document.getElementById('inputPassword')?.focus();
} else {
alert?.showAlertSimple('success', 'Password has been updated!');
}
})
}
};
},
methods: {
async updatePassword() {
if (await this.isFormValid(this.$refs.passwordFormObserver as FormContext)) {
Accounts.changePassword(this.password.old || '', this.password.new || '',
async(error: Error | Meteor.Error | Meteor.TypedError | undefined) => {
this.setNulls(this.password);
this.$refs.passwordFormObserver.resetForm();
if (error) {
console.error('Error changing password: ', error);
this.$alert.showAlertSimple('error', 'An error occurred while changing the password.');
document.getElementById('inputPassword').focus();
} else {
this.$alert.showAlertSimple('success', 'Password has been updated!');
}
});
}
}

return { password, showPass, passwordFormObserver, updatePassword };
}
});
</script>

<style scoped>

</style>
87 changes: 42 additions & 45 deletions imports/ui/components/UserLogged/UserLogged.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
import { Meteor } from 'meteor/meteor';
import { User } from '@typings/users';
import { LogoutHook } from '@typings/accounts';
import { defineComponent } from 'vue';
import { computed, defineComponent, inject, onMounted, reactive, ref } from 'vue';
import { useAuthStore } from '/imports/ui/stores/auth';
import { useRouter } from 'vue-router';
import { Injections } from '@typings/utilities';
import { Emitter, EventType } from 'mitt';

declare module Accounts {
function onLogout(func: Function): LogoutHook;
Expand All @@ -33,67 +36,61 @@ export default defineComponent({
name: 'UserLogged',
setup() {
const authStore = useAuthStore();
return { authStore };
},
data() {
return {
user: {
emails: [],
profile: {}
} as User,
onLogoutHook: null as LogoutHook | null
};
},
created() {
this.setSession();

},
mounted() {
this.emitter.on('setUserLogged', () => {
this.setSession();
const router = useRouter();
const emitter = inject<Emitter<Record<EventType, unknown>>>(Injections.Emitter);
const user: User = reactive({
emails: [],
profile: {}
});
this.onLogoutHook = Accounts.onLogout(() => {
this.closeFrontSession();
const onLogoutHook = ref<LogoutHook | null>(null);

onMounted(() => {
emitter?.on('setUserLogged', setSession);
onLogoutHook.value = Accounts.onLogout(closeFrontSession);
});
},
methods: {
closeSession() {
if (this.onLogoutHook) {
this.onLogoutHook.stop();

const closeSession = () => {
if (onLogoutHook.value) {
onLogoutHook.value?.stop();
Meteor.logout();
this.authStore.logout();
this.$router.push({ name: 'login' });
authStore.logout();
router.push({ name: 'login' });
}
},
closeFrontSession() {
if (this.onLogoutHook) {
this.onLogoutHook.stop();
this.authStore.logout();
this.$router.push({ name: 'login' });
};

const closeFrontSession = () => {
if (onLogoutHook.value) {
onLogoutHook.value?.stop();
authStore.logout();
router.push({ name: 'login'});
Comment on lines +61 to +65
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be nice to test this, only to see if it's entering to the if statement

}
},
setSession() {
};

const setSession = () => {
if (Meteor.userId() !== null) {
this.user = this.authStore.user || {
Object.assign(user, authStore.user || {
emails: [],
profile: {}
};
});
} else {
this.closeSession();
closeSession();
}
}
},
computed: {
usernameInitials() {

const usernameInitials = computed(() => {
let initials = '';
if (this.user?.username) {
const words = this.user.username.split(' ');
if (user.username) {
const words = user.username.split(' ');
initials = words.reduce((acc, word) => {
return acc + word[0];
}, '');
}
return initials.toUpperCase();
}
});

setSession();

return { user, usernameInitials, closeSession };
}
});
</script>
Loading