Clean up toasts.
This commit is contained in:
parent
2e1f09c5a6
commit
e275c5a044
|
@ -10,8 +10,6 @@
|
|||
|
||||
const { configure } = require('quasar/wrappers');
|
||||
const path = require('path');
|
||||
const { withCtx } = require('vue');
|
||||
|
||||
// Load environment variables from different files depending on if we're in development.
|
||||
let envPath = '.env.production';
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
|
@ -22,7 +20,7 @@ if (result.error) {
|
|||
throw result.error;
|
||||
}
|
||||
|
||||
module.exports = configure(function (ctx) {
|
||||
module.exports = configure(function () {
|
||||
return {
|
||||
eslint: {
|
||||
// fix: true,
|
||||
|
@ -123,7 +121,7 @@ module.exports = configure(function (ctx) {
|
|||
// directives: [],
|
||||
|
||||
// Quasar plugins
|
||||
plugins: ['Notify'],
|
||||
plugins: ['Notify', 'Dialog'],
|
||||
},
|
||||
|
||||
// animations: 'all', // --- includes all animations
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
<!--
|
||||
An item that's meant for the main UI menu, and features a dropdown with some
|
||||
account-related actions.
|
||||
-->
|
||||
<template>
|
||||
<div class="q-mx-sm">
|
||||
<q-btn-dropdown
|
||||
|
|
|
@ -52,6 +52,7 @@ export default {
|
|||
},
|
||||
accountPrivate: 'This account is private.',
|
||||
recentLifts: 'Recent Lifts',
|
||||
requestedToFollow: 'Requested to follow this user.',
|
||||
},
|
||||
userSearchPage: {
|
||||
searchHint: 'Search for a user'
|
||||
|
@ -83,6 +84,11 @@ export default {
|
|||
save: 'Save',
|
||||
undo: 'Undo'
|
||||
},
|
||||
submissionPage: {
|
||||
confirmDeletion: 'Confirm Deletion',
|
||||
confirmDeletionMsg: 'Are you sure you want to delete this submission? It will be removed permanently.',
|
||||
deletionSuccessful: 'Submission deleted successfully.'
|
||||
},
|
||||
accountMenuItem: {
|
||||
logIn: 'Login',
|
||||
profile: 'Profile',
|
||||
|
|
|
@ -47,6 +47,7 @@ export default {
|
|||
},
|
||||
accountPrivate: 'Dit account is privaat.',
|
||||
recentLifts: 'Recente liften',
|
||||
requestedToFollow: 'Gevraagd om deze gebruiker te volgen.',
|
||||
},
|
||||
userSearchPage: {
|
||||
searchHint: 'Zoek een gebruiker'
|
||||
|
@ -78,6 +79,11 @@ export default {
|
|||
save: 'Opslaan',
|
||||
undo: 'Terugzetten'
|
||||
},
|
||||
submissionPage: {
|
||||
confirmDeletion: 'Bevestig verwijderen',
|
||||
confirmDeletionMsg: 'Ben je zeker dat je dit submissie willen verwijderen? Het zal permanent verwijderd worden.',
|
||||
deletionSuccessful: 'Submissie succesvol verwijderd.'
|
||||
},
|
||||
accountMenuItem: {
|
||||
logIn: 'Inloggen',
|
||||
profile: 'Profile',
|
||||
|
|
|
@ -63,16 +63,30 @@ onMounted(async () => {
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Shows a confirmation dialog asking the user if they really want to delete
|
||||
* their submission, and if they say okay, go ahead and delete it, and bring
|
||||
* the user back to their home page that shows all their lifts.
|
||||
*/
|
||||
async function deleteSubmission() {
|
||||
// TODO: Confirm via a dialog or something before deleting.
|
||||
if (!submission.value) return;
|
||||
try {
|
||||
await api.gyms.submissions.deleteSubmission(submission.value.id, authStore);
|
||||
await router.push('/');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showApiErrorToast(i18n, quasar);
|
||||
}
|
||||
quasar.dialog({
|
||||
title: i18n.t('submissionPage.confirmDeletion'),
|
||||
message: i18n.t('submissionPage.confirmDeletionMsg'),
|
||||
cancel: true
|
||||
}).onOk(async () => {
|
||||
if (!submission.value) return;
|
||||
try {
|
||||
await api.gyms.submissions.deleteSubmission(submission.value.id, authStore);
|
||||
await router.replace(`/users/${submission.value.user.id}`);
|
||||
quasar.notify({
|
||||
message: i18n.t('submissionPage.deletionSuccessful'),
|
||||
position: 'top',
|
||||
color: 'secondary'
|
||||
})
|
||||
} catch (error) {
|
||||
showApiErrorToast(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
|
|
|
@ -101,11 +101,10 @@ import EditablePropertyRow from 'components/EditablePropertyRow.vue';
|
|||
import {WeightUnit} from 'src/api/main/submission';
|
||||
import {resolveLocale, supportedLocales} from 'src/i18n';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import {useQuasar} from 'quasar';
|
||||
import {showApiErrorToast, showSuccessToast, showWarningToast} from 'src/utils';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const quasar = useQuasar();
|
||||
const authStore = useAuthStore();
|
||||
const i18n = useI18n({useScope: 'global'});
|
||||
|
||||
|
@ -121,7 +120,7 @@ onMounted(async () => {
|
|||
// Redirect away from the page if the user isn't viewing their own settings.
|
||||
const userId = route.params.userId as string;
|
||||
if (!authStore.user || authStore.user.id !== userId) {
|
||||
await router.push(`/users/${userId}`);
|
||||
await router.replace(`/users/${userId}`);
|
||||
}
|
||||
|
||||
personalDetails.value = await api.auth.getMyPersonalDetails(authStore);
|
||||
|
@ -157,7 +156,7 @@ async function savePersonalDetails() {
|
|||
if (error.response && error.response.status === 400) {
|
||||
console.warn('bad request');
|
||||
} else {
|
||||
console.error(error);
|
||||
showApiErrorToast(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,25 +188,13 @@ async function updatePassword() {
|
|||
try {
|
||||
await api.auth.updatePassword(newPassword.value, authStore);
|
||||
newPassword.value = '';
|
||||
quasar.notify({
|
||||
message: i18n.t('userSettingsPage.passwordUpdated'),
|
||||
type: 'positive',
|
||||
position: 'top'
|
||||
});
|
||||
showSuccessToast('userSettingsPage.passwordUpdated');
|
||||
} catch (error: any) {
|
||||
if (error.response && error.response.status === 400) {
|
||||
newPassword.value = '';
|
||||
quasar.notify({
|
||||
message: i18n.t('userSettingsPage.passwordInvalid'),
|
||||
type: 'warning',
|
||||
position: 'top'
|
||||
});
|
||||
showWarningToast('userSettingsPage.passwordInvalid');
|
||||
} else {
|
||||
quasar.notify({
|
||||
message: i18n.t('generalErrors.apiError'),
|
||||
type: 'danger',
|
||||
position: 'top'
|
||||
});
|
||||
showApiErrorToast(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,7 +210,7 @@ async function onSubmitted() {
|
|||
submitButtonLabel.value = i18n.t('gymPage.submitPage.submitFailed');
|
||||
await sleep(3000);
|
||||
} else {
|
||||
showApiErrorToast(i18n, quasar);
|
||||
showApiErrorToast(error);
|
||||
}
|
||||
}
|
||||
// Otherwise, report the failed submission and give up.
|
||||
|
@ -219,7 +219,7 @@ async function onSubmitted() {
|
|||
await sleep(3000);
|
||||
}
|
||||
} catch (error: any) {
|
||||
showApiErrorToast(i18n, quasar);
|
||||
showApiErrorToast(error);
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
submitButtonLabel.value = i18n.t('gymPage.submitPage.submit');
|
||||
|
|
|
@ -63,8 +63,6 @@ import {UserFollowResponse, UserProfile} from 'src/api/main/auth';
|
|||
import api from 'src/api/main';
|
||||
import {useRoute} from 'vue-router';
|
||||
import {useAuthStore} from 'stores/auth-store';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import {useQuasar} from 'quasar';
|
||||
import {showApiErrorToast, showInfoToast} from 'src/utils';
|
||||
import PageMenu from 'components/PageMenu.vue';
|
||||
import UserSubmissionsPage from 'pages/user/UserSubmissionsPage.vue';
|
||||
|
@ -75,8 +73,6 @@ import {useDevStore} from 'stores/dev-store';
|
|||
const route = useRoute();
|
||||
const authStore = useAuthStore();
|
||||
const devStore = useDevStore();
|
||||
const i18n = useI18n();
|
||||
const quasar = useQuasar();
|
||||
|
||||
const profile: Ref<UserProfile | undefined> = ref();
|
||||
const isOwnUser = ref(false);
|
||||
|
@ -102,7 +98,7 @@ async function loadUser(id: string) {
|
|||
isOwnUser.value = authStore.loggedIn && profile.value.id === authStore.user?.id;
|
||||
} catch (error: any) {
|
||||
if (!(error.response && error.response.status === 404)) {
|
||||
showApiErrorToast(i18n, quasar);
|
||||
showApiErrorToast(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,10 +110,10 @@ async function followUser() {
|
|||
if (result === UserFollowResponse.FOLLOWED) {
|
||||
await loadUser(profile.value.id);
|
||||
} else if (result === UserFollowResponse.REQUESTED) {
|
||||
showInfoToast(quasar, 'Requested to follow this user!');
|
||||
showInfoToast('userPage.requestedToFollow');
|
||||
}
|
||||
} catch (error) {
|
||||
showApiErrorToast(i18n, quasar);
|
||||
showApiErrorToast(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +124,7 @@ async function unfollowUser() {
|
|||
await api.auth.unfollowUser(profile.value.id, authStore);
|
||||
await loadUser(profile.value.id);
|
||||
} catch (error) {
|
||||
showApiErrorToast(i18n, quasar);
|
||||
showApiErrorToast(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {useI18n} from 'vue-i18n';
|
||||
import {useQuasar} from 'quasar';
|
||||
import {useAuthStore} from 'stores/auth-store';
|
||||
import {onMounted, ref, Ref} from 'vue';
|
||||
import api from 'src/api/main';
|
||||
|
@ -30,20 +28,14 @@ interface Props {
|
|||
}
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const i18n = useI18n();
|
||||
const quasar = useQuasar();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
const submissions: Ref<ExerciseSubmission[]> = ref([]);
|
||||
const loader = new InfinitePageLoader(submissions, async paginationOptions => {
|
||||
try {
|
||||
return await api.users.getSubmissions(props.userId, authStore, paginationOptions);
|
||||
} catch (error: any) {
|
||||
if (error.response) {
|
||||
showApiErrorToast(i18n, quasar);
|
||||
} else {
|
||||
console.log(error);
|
||||
}
|
||||
} catch (error) {
|
||||
showApiErrorToast(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,21 +1,46 @@
|
|||
import {QVueGlobals} from 'quasar';
|
||||
import {useQuasar} from 'quasar';
|
||||
import {useI18n} from 'vue-i18n';
|
||||
|
||||
/**
|
||||
* Sleeps for a given number of milliseconds before resolving.
|
||||
* @param ms The milliseconds to sleep for.
|
||||
*/
|
||||
export const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
||||
|
||||
export function showApiErrorToast(i18n: any, quasar: QVueGlobals) {
|
||||
function showToast(type: string, messageKey: string) {
|
||||
const quasar = useQuasar();
|
||||
const i18n = useI18n();
|
||||
quasar.notify({
|
||||
message: i18n.t('generalErrors.apiError'),
|
||||
type: 'danger',
|
||||
message: i18n.t(messageKey),
|
||||
type: type,
|
||||
position: 'top'
|
||||
});
|
||||
}
|
||||
|
||||
export function showInfoToast(quasar: QVueGlobals, translatedMessage: string) {
|
||||
quasar.notify({
|
||||
message: translatedMessage,
|
||||
type: 'info',
|
||||
position: 'top'
|
||||
});
|
||||
/**
|
||||
* Shows a generic API error message toast notification, for when an API call
|
||||
* fails to return any status. This should only be called within the context of
|
||||
* a Vue component, as it utilizes some dependencies that are only available
|
||||
* then.
|
||||
* @param error The error to display.
|
||||
*/
|
||||
export function showApiErrorToast(error?: unknown) {
|
||||
showToast('danger', 'generalErrors.apiError');
|
||||
if (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
export function showInfoToast(messageKey: string) {
|
||||
showToast('info', messageKey);
|
||||
}
|
||||
|
||||
export function showSuccessToast(messageKey: string) {
|
||||
showToast('positive', messageKey);
|
||||
}
|
||||
|
||||
export function showWarningToast(messageKey: string) {
|
||||
showToast('warning', messageKey);
|
||||
}
|
||||
|
||||
export function getDocumentHeight() {
|
||||
|
|
Loading…
Reference in New Issue