import { h } from 'vue'; import StatusIcon from '../Global/StatusIcon'; import i18n from '@/i18n'; const BVToastMixin = { components: { StatusIcon, }, methods: { $_BVToastMixin_createTitle(title, status) { const statusIcon = h(StatusIcon, { status }); return h('strong', { class: 'toast-icon' }, [statusIcon, title]); }, $_BVToastMixin_createBody(messageBody) { if (Array.isArray(messageBody)) { return messageBody.map((message) => h('p', { class: 'mb-0' }, message)); } else { return [h('p', { class: 'mb-0' }, messageBody)]; } }, $_BVToastMixin_createTimestamp() { const timestamp = this.$filters.formatTime(new Date()); return h('p', { class: 'mt-3 mb-0' }, timestamp); }, $_BVToastMixin_createRefreshAction() { return h( 'BLink', { class: 'd-inline-block mt-3', onClick: () => { require('@/eventBus').default.$emit('refresh-application'); }, }, i18n.global.t('global.action.refresh'), ); }, $_BVToastMixin_initToast(body, title, variant) { // Use global toast plugin (works with Options API) // Extract text content from VNodes for display // Extract title text from VNode const titleText = typeof title === 'string' ? title : title?.children?.[1] || title?.children || ''; // Extract body text from VNode array // Each VNode (paragraph) should be on its own line const bodyLines = Array.isArray(body) ? body.map((node) => { if (typeof node === 'string') return node; // Extract text from VNode children const text = node?.children || node?.props?.children || ''; // Ensure timestamps and other paragraphs are on separate lines return text; }) : [typeof body === 'string' ? body : body?.children || '']; // Join with newlines to ensure timestamps appear on their own line const bodyText = bodyLines.filter(Boolean).join('\n'); // Show toast via global plugin if (this.$toast) { this.$toast.show({ body: bodyText, props: { title: titleText, variant, isStatus: true, solid: false, // Use light backgrounds with dark text (not solid colors) // Success toasts auto-dismiss after 10s, others stay until closed interval: variant === 'success' ? 10000 : 0, // Note: Progress bar hidden via CSS in _toasts.scss (JS props to hide progress bar don't work as documented in Bootstrap Vue Next 0.40.8) }, }); } else { // Fallback: log to console /* eslint-disable no-console */ console[variant === 'danger' ? 'error' : 'log']( `[toast:${variant}]`, bodyText, ); /* eslint-enable no-console */ } }, successToast( message, { title: t = i18n.global.t('global.status.success'), timestamp, refreshAction, } = {}, ) { const body = this.$_BVToastMixin_createBody(message); const title = this.$_BVToastMixin_createTitle(t, 'success'); if (refreshAction) body.push(this.$_BVToastMixin_createRefreshAction()); if (timestamp) { body.push(' '); // Extra newline for spacing above timestamp body.push(this.$_BVToastMixin_createTimestamp()); } this.$_BVToastMixin_initToast(body, title, 'success'); }, errorToast( message, { title: t = i18n.global.t('global.status.error'), timestamp, refreshAction, } = {}, ) { const body = this.$_BVToastMixin_createBody(message); const title = this.$_BVToastMixin_createTitle(t, 'danger'); if (refreshAction) body.push(this.$_BVToastMixin_createRefreshAction()); if (timestamp) { body.push(' '); // Extra newline for spacing above timestamp body.push(this.$_BVToastMixin_createTimestamp()); } this.$_BVToastMixin_initToast(body, title, 'danger'); }, warningToast( message, { title: t = i18n.global.t('global.status.warning'), timestamp, refreshAction, } = {}, ) { const body = this.$_BVToastMixin_createBody(message); const title = this.$_BVToastMixin_createTitle(t, 'warning'); if (refreshAction) body.push(this.$_BVToastMixin_createRefreshAction()); if (timestamp) { body.push(' '); // Extra newline for spacing above timestamp body.push(this.$_BVToastMixin_createTimestamp()); } this.$_BVToastMixin_initToast(body, title, 'warning'); }, infoToast( message, { title: t = i18n.global.t('global.status.informational'), timestamp, refreshAction, } = {}, ) { const body = this.$_BVToastMixin_createBody(message); const title = this.$_BVToastMixin_createTitle(t, 'info'); if (refreshAction) body.push(this.$_BVToastMixin_createRefreshAction()); if (timestamp) { body.push(' '); // Extra newline for spacing above timestamp body.push(this.$_BVToastMixin_createTimestamp()); } this.$_BVToastMixin_initToast(body, title, 'info'); }, }, }; export default BVToastMixin;