Skip to content

Commit

Permalink
Components: Interaction-dialog: Add return to dialog actions
Browse files Browse the repository at this point in the history
Signed-off-by: Arturo Manzoli <[email protected]>
  • Loading branch information
ArturoManzoli committed Jun 7, 2024
1 parent 5648aa6 commit ed196e4
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 30 deletions.
65 changes: 56 additions & 9 deletions src/components/InteractionDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
<v-card :max-width="maxWidth || 600" class="main-dialog px-2 rounded-lg">
<v-card-title>
<div
class="flex justify-center test-center pt-2 mb-2 text-[20px] font-bold text-nowrap text-ellipsis overflow-x-hidden"
class="flex justify-center test-center pt-2 mb-1 text-[20px] font-bold text-nowrap text-ellipsis overflow-x-hidden"
:class="`w-[${maxWidth}px]`"
>
{{ title }}
</div>
</v-card-title>
<v-card-text class="pb-5">
<div class="flex justify-center align-center w-full mb-3">
<v-icon v-if="variant" size="38" color="white" class="mr-8">{{
<v-icon v-if="variant" size="46" :color="variant === 'success' ? 'green' : 'yellow'" class="mr-8 ml-2">{{
variant === 'info'
? 'mdi-information'
: variant === 'warning'
? 'mdi-alert'
? 'mdi-alert-rhombus'
: variant === 'error'
? 'mdi-alert-circle'
: 'mdi-check-circle'
Expand Down Expand Up @@ -43,13 +43,13 @@
:color="button.color || undefined"
:class="button.class || undefined"
:disabled="button.disabled || false"
@click="button.action"
@click="handleAction(button.action)"
>
{{ button.text }}
</v-btn>
</div>
<div v-else class="flex w-full px-1 py-2 justify-end">
<v-btn size="small" variant="text" @click="internalShowDialog = false">Close</v-btn>
<v-btn size="small" variant="text" @click="handleAction(() => (internalShowDialog = false))">Close</v-btn>
</div>
</v-card-actions>
</v-card>
Expand All @@ -63,24 +63,65 @@ import { useInteractionDialog } from '@/composables/interactionDialog'
const { closeDialog } = useInteractionDialog()
/* eslint-disable jsdoc/require-jsdoc */
/**
*
*/
interface Action {
/**
*
*/
text: string
/**
*
*/
size?: string
/**
*
*/
color?: string
/**
*
*/
class?: string
/**
*
*/
disabled?: boolean
/**
*
*/
action: () => void
}
const props = withDefaults(
defineProps<{
/**
*
*/
showDialog: boolean
/**
*
*/
title: string
/**
*
*/
contentComponent: string
/**
*
*/
maxWidth: number
/**
*
*/
actions: Action[]
/**
*
*/
variant: string
/**
*
*/
message: string
}>(),
{
Expand All @@ -94,7 +135,7 @@ const props = withDefaults(
}
)
const emit = defineEmits(['update:showDialog'])
const emit = defineEmits(['update:showDialog', 'confirmed', 'dismissed'])
const internalShowDialog = ref(props.showDialog)
Expand All @@ -109,15 +150,21 @@ watch(internalShowDialog, (newVal) => {
if (!newVal) {
closeDialog()
emit('update:showDialog', newVal)
emit('dismissed')
}
})
const handleAction = (action: () => void): void => {
action()
emit('confirmed')
}
</script>

<style scoped>
.main-dialog {
color: white;
border: 1px solid #fafafa44;
background-color: #aaaaaa99;
border: 1px solid #fafafa33;
background-color: #aaaaaa44;
backdrop-filter: blur(30px);
box-shadow: 0px 4px 4px 0px #0000004c, 0px 8px 12px 6px #00000026;
}
Expand Down
88 changes: 67 additions & 21 deletions src/composables/interactionDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,69 @@ import InteractionDialogComponent from '@/components/InteractionDialog.vue'
import vuetify from '@/plugins/vuetify'
import { DialogActions } from '@/types/general'

/* eslint-disable jsdoc/require-jsdoc */
/**
* Options to configure the interaction dialog.
*/
interface DialogOptions {
/**
* The message to display in the dialog.
* @type {string}
*/
message: string

/**
* The variant type of the dialog (e.g., 'info', 'warning', 'error', 'success').
* @type {string}
*/
variant: string

/**
* The title of the dialog.
* @type {string}
*/
title?: string

/**
* The actions to display in the dialog.
* Each action should be an object containing text, size, color, class, disabled, and action properties.
* @type {DialogActions[]}
*/
actions?: DialogActions[]

/**
* The maximum width of the dialog in pixels.
* @type {number}
*/
maxWidth?: number
}

/**
*
*/
interface DialogResult {
/**
*
*/
isConfirmed: boolean
}

let resolveFn: (value: DialogResult | PromiseLike<DialogResult>) => void
let rejectFn: (reason?: DialogResult) => void

/**
* Provides methods to control the interaction dialog.
* @returns {object} - An object containing the showDialog and closeDialog methods.
*/
export function useInteractionDialog(): {
/**
*
* Shows the dialog with the provided options.
* @param {DialogOptions} options - Options to configure the dialog.
* @returns {Promise<{ isConfirmed: boolean }>} - A promise that resolves or rejects based on user action.
*/
showDialog: (options: DialogOptions) => void
showDialog: (options: DialogOptions) => Promise<DialogResult>
/**
*
* Closes the dialog.
* @returns {void}
*/
closeDialog: () => void
} {
Expand All @@ -47,34 +90,37 @@ export function useInteractionDialog(): {

let dialogApp: App<Element> | null = null

/**
* Mounts the dialog component to the DOM.
* @returns {void}
*/
const mountDialog = (): void => {
const mountPoint = document.createElement('div')
document.body.appendChild(mountPoint)
dialogApp = createApp(InteractionDialogComponent, dialogProps)
dialogApp = createApp(InteractionDialogComponent, {
...dialogProps,
onConfirmed: () => {
if (resolveFn) resolveFn({ isConfirmed: true })
},
onDismissed: () => {
if (rejectFn) rejectFn({ isConfirmed: false })
},
})
dialogApp.use(vuetify)
dialogApp.mount(mountPoint)
}

/**
* Shows the dialog with the provided options.
* @param {DialogOptions} options - Options to configure the dialog.
* @returns {void}
*/
const showDialog = (options: DialogOptions): void => {
Object.assign(dialogProps, options, { showDialog: true })
mountDialog()
const showDialog = (options: DialogOptions): Promise<DialogResult> => {
return new Promise((resolve, reject) => {
Object.assign(dialogProps, options, { showDialog: true })
resolveFn = resolve
rejectFn = reject
mountDialog()
})
}

/**
* Closes the dialog.
* @returns {void}
*/
const closeDialog = (): void => {
dialogProps.showDialog = false
if (dialogApp) {
dialogApp.unmount()
dialogApp = null
}
}

onUnmounted(() => {
Expand Down

0 comments on commit ed196e4

Please sign in to comment.