User Support

Ticket system for communicating with users

Ticket Submit Component

The supportTicketSubmit component displays a form that lets the signed-in user submit a new ticket, of a type they pick or that the page forces.

Property Description
ticketType The code of a ticket type to give every ticket from this page, even a hidden type. Leave it empty to let the user pick a type. See Forcing a Type.
redirect The page to open after a ticket is submitted, with the new ticket's ID as the id URL parameter. This is usually the page with the Ticket component.

Basic Usage

The component only accepts tickets from a signed-in user, so restrict the page to signed-in users with the RainLab.User session component.

title = "Submit Ticket"
url = "/support/submit"
layout = "default"

[session]
security = "user"
redirect = "account/login"

[supportTicketSubmit]
redirect = "support/ticket"
==
{% component "supportTicketSubmit" %}

The default form asks for a ticket type first. When the user picks one, it shows the type's description with the subject, content and attachment fields.

Page Variables

The ticketTypes method of the component returns the ticket types that users can pick, sorted by name. Hidden types are left out.

{% set ticketTypes = supportTicketSubmit.ticketTypes %}

The component also sets these page variables.

Variable Description
ticketTypeCode The ticketType property value.
ticketType The forced ticket type. Without a forced type, it is the visible type posted as type_id, or null.

The following page submits a ticket with its own markup.

title = "Submit Ticket"
url = "/support/submit"
layout = "default"

[session]
security = "user"
redirect = "account/login"

[supportTicketSubmit]
redirect = "support/ticket"
==
{{ form_ajax('onSubmitTicket', { files: true, flash: true, validate: true }) }}
    <label for="ticketType">
        Ticket type
    </label>
    <select name="type_id" id="ticketType">
        <option value="">
            Select a ticket type
        </option>
        {% for type in supportTicketSubmit.ticketTypes %}
            <option value="{{ type.id }}">
                {{ type.name }}
            </option>
        {% endfor %}
    </select>
    <div data-validate-for="type_id"></div>

    <label for="subject">
        Subject
    </label>
    <input name="subject" id="subject" type="text" maxlength="255" />
    <div data-validate-for="subject"></div>

    <label for="content">
        Message
    </label>
    <textarea name="content" id="content" rows="8"></textarea>
    <div data-validate-for="content"></div>

    <input name="files[]" type="file" multiple />
    <div data-validate-for="files"></div>

    <button type="submit" data-attach-loading>
        Submit ticket
    </button>
{{ form_close() }}

AJAX Handlers

The component provides the following AJAX handlers.

Handler Description
onSubmitTicket Validates and saves the new ticket with its attachments, then redirects.
onUpdateTicketType Loads the posted ticket type into the ticketType page variable, so the form can show its description.

Submitting a Ticket

The onSubmitTicket handler accepts the following fields.

Field Description
subject The subject. Required, and at most 255 characters.
content The ticket text, in Markdown. Required, and at most 50,000 characters.
type_id The ID of a ticket type from ticketTypes. Optional, and ignored when the ticketType property is set.
files[] Files to attach. See Attachments.
redirect Optional. A page name, or a path on this site, that replaces the redirect property.

The handler saves the ticket for the signed-in user with the New status, and staff receive the new-ticket mail. Then it sets the flash message The ticket has been posted successfully. and redirects to the redirect page with the new ticket's ID. When no redirect is set, it redirects back to the same page, which clears the form.

A posted redirect that is not a page name is treated as a path on this site, so the scheme and host of a full URL are dropped.

Showing the Type Description

The default form calls the onUpdateTicketType handler when the user picks a type, and updates the message-form partial with the type's description and the remaining fields.

<select
    name="type_id"
    data-request="onUpdateTicketType"
    data-request-update="{ '@message-form': '#partialMessageForm' }">
    <option value="">
        Select a ticket type
    </option>
    {% for type in ticketTypes %}
        <option value="{{ type.id }}">
            {{ type.name }}
        </option>
    {% endfor %}
</select>

<div id="partialMessageForm">
    {% partial '@message-form' %}
</div>

The handler refuses a hidden or unknown type with Ticket type not found. An empty type_id clears the type, and the form asks for one again.

Forcing a Type

Set the ticketType property to a type code to give every ticket from the page that type, even when the type is hidden. The handler ignores any posted type_id, and the default form leaves out the type select.

[supportTicketSubmit]
ticketType = "technical"
redirect = "support/ticket"

When no type has that code, the default form shows a notice in place of the fields, and the handler refuses every submission with the message This ticket type is not available. A warning is also written to the log. To show the same notice in your own markup, check the page variables.

{% if ticketTypeCode and not ticketType %}
    <p>
        This ticket type is not available.
    </p>
{% else %}
    {{ form_ajax('onSubmitTicket', { files: true, flash: true, validate: true }) }}
        <!-- Subject, content and attachment fields -->
    {{ form_close() }}
{% endif %}

See Ticket Types for hidden types and type codes.

Partials

The component renders the following partials.

Partial Description
default Wraps the form in the responsiv-support element, with the ticket type select when no type is forced.
message-form The type description with the subject, content and attachment fields, or a notice asking for a type.
flash-messages Shared. Shows the flash messages.

To change one of them, copy it into the partials/supportTicketSubmit folder of your theme. See Overriding Partials.

Rules

  • Signed-in users. The handler refuses a guest with You should be logged in. The new ticket always belongs to the signed-in user.
  • Posted values. Only the subject, content, type and files are taken from the form. Other posted values, such as a status or an assignee, are ignored.
  • Ticket types. A posted type_id must be one of the types in ticketTypes. Otherwise the handler refuses it with Please select a valid ticket type. under the type_id field.
  • Validation. Errors are reported under the subject and content fields.
  • Attachments. Every file is checked against the attachment rules before the ticket is saved, and errors are reported under the files field.