Skip to content

ComplaintCreateDialog ​

A modal "New complaint" dialog: CreateDialog provides the chrome, ComplaintForm the body, and the dialog's footer drives the form's validation. Open it with v-model:open and listen for submit with the validated payload.

vue
<script setup lang="ts">
import { ref } from "vue"
import RyderComplaintCreateDialog from "@opeolluwa/ryder/components/complaints/ComplaintCreateDialog.vue"
import type { CreateComplaintPayload } from "@opeolluwa/ryder/types"

const open = ref(false)
const loading = ref(false)

function onSubmit(payload: CreateComplaintPayload) {
  // POST the payload, then flip `loading` back off and close.
}
</script>

<template>
  <RyderComplaintCreateDialog
    v-model:open="open"
    :loading="loading"
    :orders="orders"
    @submit="onSubmit"
    @cancel="open = false"
  />
</template>

Examples ​

vue
<script setup lang="ts">
import { ref } from "vue";
import ComplaintCreateDialog from "../../../src/components/complaints/ComplaintCreateDialog.vue";
import { orders } from "./fixtures";
import type { CreateComplaintPayload } from "../../../src/types/complaints";

const open = ref(false);
const loading = ref(false);
const lastSubmit = ref("—");

// The dialog stays open until the (simulated) POST lands, then closes itself.
async function onSubmit(payload: CreateComplaintPayload) {
  lastSubmit.value = JSON.stringify(payload);
  loading.value = true;

  await new Promise((resolve) => setTimeout(resolve, 500));

  loading.value = false;
  open.value = false;
}
</script>

<template>
  <div>
    <button
      type="button"
      class="rounded-lg bg-gray-900 px-4 py-2 text-sm text-white dark:bg-white dark:text-gray-900"
      @click="open = true"
    >
      New complaint
    </button>

    <ComplaintCreateDialog
      v-model:open="open"
      :loading="loading"
      :orders="orders"
      @submit="onSubmit"
      @cancel="lastSubmit = 'cancel'"
    />

    <p class="mt-3 text-xs text-gray-500 dark:text-white/40">
      Last submit: {{ lastSubmit }}
    </p>
  </div>
</template>

Props ​

PropTypeDefaultDescription
v-model:openbooleanfalseDialog visibility (defineModel).
loadingboolean—Disables the dialog's Submit button and the form's submit (the inner form gets show-actions: false, so only the footer shows).
ordersArray<{ identifier: string; status?: string; itemsCount?: number }>—Forwarded to the form; its [] default applies when omitted.
ordersLoadingboolean—Disables the order select while orders load.
orderStatusLabel(status: any) => string—Option-label status formatter; the form's default applies when omitted.
orderItemCount(order: any) => number—Option-label item counter; the form's default applies when omitted.

Emits ​

EventPayloadDescription
update:open[value: boolean]The v-model write — fires on every open change.
submit[payload: CreateComplaintPayload]The form validated; payload relayed from ComplaintForm.
cancel[]Cancel clicked: the dialog closes, the form resets, then this fires.

Slots ​

None. The dialog's title, description and footer labels are fixed (New complaint / Tell us what went wrong… / Submit complaint).

Notes ​

  • Wiring: the footer's Submit calls the inner form's submit(), which runs valibot validation first — a submit emit means the payload is already clean. Cancel closes (open = false), calls the form's reset() so the next open starts blank, then re-emits cancel.
  • Exposes reset() for hosts that want to clear the form without closing (e.g. after a failed POST).
  • The inner form renders with show-actions: false, so Cancel/Submit live only in the dialog footer — there is no duplicated button row.
  • Inherits every validation rule and quirk of ComplaintForm — the form is the same component with show-actions: false.
  • Rendered through Dialog, so below lg it becomes a bottom sheet; UModal on desktop.