Complete toast implementation
This commit is contained in:
parent
0679fe04ef
commit
058c5e5b77
|
@ -9,21 +9,18 @@
|
|||
<component :is="Component" />
|
||||
</transition>
|
||||
</router-view>
|
||||
<button @click.prevent="showToast('howdy', 'danger')">Show toast</button>
|
||||
</main>
|
||||
<app-footer />
|
||||
<div aria-live="polite" aria-atomic="true">
|
||||
<div class="toast-container position-absolute p-3 bottom-0 start-50 translate-middle-x" id="toasts"></div>
|
||||
</div>
|
||||
<app-toaster />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { Toast } from 'bootstrap'
|
||||
import AppFooter from './components/layout/AppFooter.vue'
|
||||
import AppNav from './components/layout/AppNav.vue'
|
||||
import AppToaster from './components/layout/AppToaster.vue'
|
||||
import TitleBar from './components/layout/TitleBar.vue'
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.min.css'
|
||||
|
@ -34,12 +31,8 @@ export default defineComponent({
|
|||
components: {
|
||||
AppFooter,
|
||||
AppNav,
|
||||
AppToaster,
|
||||
TitleBar
|
||||
},
|
||||
setup () {
|
||||
return {
|
||||
showToast
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -52,33 +45,6 @@ export default defineComponent({
|
|||
export function yesOrNo (cond : boolean) : string {
|
||||
return cond ? 'Yes' : 'No'
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a toast notification
|
||||
*
|
||||
* @param text The text of the notification
|
||||
* @param type The type of notification to show (defaults to 'success')
|
||||
* @param heading The optional text to use for the heading
|
||||
*/
|
||||
export function showToast (text : string, type = 'success', heading : string | undefined) : void {
|
||||
let header : HTMLDivElement | undefined
|
||||
if (heading) {
|
||||
header = document.createElement('div')
|
||||
header.className = 'toast-header'
|
||||
header.innerHTML = 'The Header'
|
||||
}
|
||||
const body = document.createElement('div')
|
||||
body.className = 'toast-body'
|
||||
body.innerHTML = text
|
||||
|
||||
const toast = document.createElement('div')
|
||||
if (header) toast.appendChild(header)
|
||||
toast.appendChild(body)
|
||||
toast.className = `toast bg-${type} text-white`
|
||||
|
||||
;(document.getElementById('toasts') as HTMLDivElement).appendChild(toast)
|
||||
new Toast(toast).show()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
83
src/JobsJobsJobs/App/src/components/layout/AppToaster.vue
Normal file
83
src/JobsJobsJobs/App/src/components/layout/AppToaster.vue
Normal file
|
@ -0,0 +1,83 @@
|
|||
<template>
|
||||
<div aria-live="polite" aria-atomic="true">
|
||||
<div class="toast-container position-absolute p-3 bottom-0 start-50 translate-middle-x" id="toasts"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { Toast } from 'bootstrap'
|
||||
|
||||
/** Remove a toast once it's hidden */
|
||||
const removeToast = (event : Event) => (event.target as HTMLDivElement).remove()
|
||||
|
||||
/** Create a toast, add it to the DOM, and show it */
|
||||
const createToast = (level : 'success' | 'warning' | 'danger', message : string, process : string | undefined) => {
|
||||
let header : HTMLDivElement | undefined
|
||||
if (level !== 'success') {
|
||||
// Create a heading, optionally including the process that generated the message
|
||||
const heading = (typ : string) : string => {
|
||||
const proc = process ? ` (${process})` : ''
|
||||
return `<span class="me-auto"><strong>${typ.toUpperCase()}</strong>${proc}</span>`
|
||||
}
|
||||
header = document.createElement('div')
|
||||
header.className = 'toast-header'
|
||||
header.innerHTML = heading(level === 'warning' ? level : 'error')
|
||||
// Include a close button, as these will not auto-close
|
||||
const close = document.createElement('button')
|
||||
close.type = 'button'
|
||||
close.className = 'btn-close'
|
||||
close.setAttribute('data-bs-dismiss', 'toast')
|
||||
close.setAttribute('aria-label', 'Close')
|
||||
header.appendChild(close)
|
||||
}
|
||||
const body = document.createElement('div')
|
||||
body.className = 'toast-body'
|
||||
body.innerHTML = message
|
||||
|
||||
const toastEl = document.createElement('div')
|
||||
toastEl.className = `toast bg-${level} text-white`
|
||||
toastEl.setAttribute('role', 'alert')
|
||||
toastEl.setAttribute('aria-live', 'assertlive')
|
||||
toastEl.setAttribute('aria-atomic', 'true')
|
||||
toastEl.addEventListener('hidden.bs.toast', removeToast)
|
||||
if (header) toastEl.appendChild(header)
|
||||
toastEl.appendChild(body)
|
||||
|
||||
;(document.getElementById('toasts') as HTMLDivElement).appendChild(toastEl)
|
||||
new Toast(toastEl, { autohide: level === 'success' }).show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a success toast
|
||||
*
|
||||
* @param message The message to be displayed
|
||||
*/
|
||||
export function toastSuccess (message : string) : void {
|
||||
createToast('success', message, undefined)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a warning toast
|
||||
*
|
||||
* @param message The message to be displayed
|
||||
* @param process The process which generated the warning (optional)
|
||||
*/
|
||||
export function toastWarning (message : string, process : string | undefined) : void {
|
||||
createToast('warning', message, process)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an error toast
|
||||
*
|
||||
* @param message The message to be displayed
|
||||
* @param process The process which generated the error (optional)
|
||||
*/
|
||||
export function toastError (message : string, process : string | undefined) : void {
|
||||
createToast('danger', message, process)
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'AppToaster'
|
||||
})
|
||||
</script>
|
|
@ -9,6 +9,7 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { toastSuccess } from '@/components/layout/AppToaster.vue'
|
||||
import { useStore } from '@/store'
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -19,8 +20,8 @@ export default defineComponent({
|
|||
|
||||
onMounted(() => {
|
||||
store.commit('clearUser')
|
||||
toastSuccess('Log Off Successful | <strong>Have a Nice Day!</strong>')
|
||||
router.push('/')
|
||||
// TODO: toast
|
||||
})
|
||||
|
||||
return { }
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
<page-title title="Account Deletion Options" />
|
||||
<h3>Account Deletion Options</h3>
|
||||
|
||||
<p v-if="error !== ''">{{error}}</p>
|
||||
|
||||
<h4>Option 1 – Delete Your Profile</h4>
|
||||
<p>
|
||||
Utilizing this option will remove your current employment profile and skills. This will preserve any success
|
||||
|
@ -38,9 +36,10 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { defineComponent } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import api, { LogOnSuccess } from '@/api'
|
||||
import { toastError, toastSuccess } from '@/components/layout/AppToaster.vue'
|
||||
import { useStore } from '@/store'
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -49,16 +48,13 @@ export default defineComponent({
|
|||
const store = useStore()
|
||||
const router = useRouter()
|
||||
|
||||
/** Error message encountered during actions */
|
||||
const error = ref('')
|
||||
|
||||
/** Delete the profile only; redirect to home page on success */
|
||||
const deleteProfile = async () => {
|
||||
const resp = await api.profile.delete(store.state.user as LogOnSuccess)
|
||||
if (typeof resp === 'string') {
|
||||
error.value = resp
|
||||
toastError(resp, 'Deleting Profile')
|
||||
} else {
|
||||
// TODO: notify
|
||||
toastSuccess('Profile Deleted Successfully')
|
||||
router.push('/citizen/dashboard')
|
||||
}
|
||||
}
|
||||
|
@ -67,16 +63,15 @@ export default defineComponent({
|
|||
const deleteAccount = async () => {
|
||||
const resp = await api.citizen.delete(store.state.user as LogOnSuccess)
|
||||
if (typeof resp === 'string') {
|
||||
error.value = resp
|
||||
toastError(resp, 'Deleting Account')
|
||||
} else {
|
||||
store.commit('clearUser')
|
||||
// TODO: notify
|
||||
toastSuccess('Account Deleted Successfully')
|
||||
router.push('/so-long/success')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
error,
|
||||
deleteProfile,
|
||||
deleteAccount
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user