Ticket Client Feedback Project
Preview
Description
Feedback Form is built with Next.js and other technologies to make it reusable for clients to report problems through tickets.
Features
- Anonymous Authentication on the Server
- Form Validation
- Query String Injection
- Post Message Injection
- New Ticket Creation
- Print Screen (Internal and External)
Technologies
- Next.js 14
- Javascript and Typescript
- React Hook Form
- Yup
- Tailwind CSS
- CSS
- HTML2Canvas
- Axios
- Cookies Next
- React Icons
- And many other Javascript libraries
Form Fields
- Some fields which are visible on the frontend and are required to be filled.
- Other than the required fields, there're two features one for
URL
and other isScreenshot
which will automatically be passed to API behind the scenes. The screenshot is taken with HTML2Canvas library and URL is taken from browser window.
Required fields to be filled by the user
- First Name
- Last Name
- Description
- Phone Number
- Ticket Type (The first option will be auto-selected so you won't see any error if you forget to select any option)
- Ticket Impact (The first option will be auto-selected so you won't see any error if you forget to select any option)
IFrame integration in other projects
Step by step on how to add the ticket feedback iframe in other projects, all examples are from the PHPR ERP project.
Step 1: Create a "feedbackModal" view
Create a view that will contain the feedback modal.
-
First, you need to add the links for the feedback css and icons. Redefine css class if necessary.
<link rel="stylesheet" href="https://ticket-feedback-form.phpr.link/assets/css/all-forms-iframe-only.css" /> <link rel="icon" href="https://ticket-feedback-form.phpr.link/assets/images/favicon.ico" type="image/x-icon" /> <link rel="apple-touch-icon" href="https://ticket-feedback-form.phpr.link/assets/images/favicon.ico" /> {# Redefinition of position for closeBtn, because for some reason it was a bit off in PHPR. #} <style> #closeBtn { top: 12px; right: 12px; } </style>
-
Second, add a div to contain the iframe, then a div wrapper inside the container.
<div id="iframeContainer" class="iframeContainer" hidden> <div id="frame-wrapper"> </div> </div>
Inside the wrapper, add the close button (anchor) before the iframe. Just after the close button, add the iframe.
<div id="iframeContainer" class="iframeContainer" hidden> <div id="frame-wrapper"> <a href="#" id="closeBtn" title="Close">×</a> <iframe src="https://ticket-feedback-form.phpr.link/{{ locale }}/feedback" frameborder="0" allowfullscreen id="frame1" loading="lazy" onload="sendInformationsToiFrame(this, '{{ app.user.person.firstName }}', '{{ app.user.person.lastName }}', '{{ app.user.person.defaultCoordinate.contactsEmail }}', '{{ app.user.person.defaultCoordinate.contactsTel }}')" > </iframe> </div> </div>
-
After the iframeContainer div is completed with the iframe, add the necessary JS to make everything work together.
<script> var modalLink = document.querySelector(".open-modal"); var modalContainer = document.getElementById("iframeContainer"); var closeBtn = document.getElementById("closeBtn"); var iframe = document.getElementById("frame"); function openModal() { modalContainer.style.display = "flex"; } function closeModal() { modalContainer.style.display = "none"; } modalLink.addEventListener("click", function (event) { event.preventDefault(); openModal(); }); closeBtn.addEventListener("click", function (event) { closeModal(); }); var iframeLinks = document.querySelectorAll(".iframe-link"); iframeLinks.forEach(function (link) { link.style.display = "inline"; }); </script>
-
At the end of the file, add the JS sources.
{# Ticket feedback JS #} {# Needs html2canvas for screenshots #} <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script> {# Should be PHPC CDN + fallback local #} <script src="https://ticket-feedback-form.phpr.link/assets/js/new/sendAllInformationsToiFrame.js"></script>
Complete example from PHPR (the view is made using Twig):
<link
rel="stylesheet"
href="https://ticket-feedback-form.phpr.link/assets/css/all-forms-iframe-only.css"
/>
<link
rel="icon"
href="https://ticket-feedback-form.phpr.link/assets/images/favicon.ico"
type="image/x-icon"
/>
<link
rel="apple-touch-icon"
href="https://ticket-feedback-form.phpr.link/assets/images/favicon.ico"
/>
{# Redefinition of position for closeBtn, because for some reason it was a bit off in PHPR. #}
<style>
#closeBtn {
top: 12px;
right: 12px;
}
</style>
<div id="iframeContainer" class="iframeContainer" hidden>
<div id="frame-wrapper">
<a href="#" id="closeBtn" title="Close">×</a>
{% if app.request.locale is defined %}
{% set locale = app.request.locale %}
{% if locale == 'fr_CA' %}
{% set locale = 'fr' %}
{% elseif locale == 'en_CA' %}
{% set locale = 'en' %}
{% else %}
{% set locale = 'fr' %}
{% endif %}
{% else %}
{% set locale = 'fr' %}
{% endif %}
{% if app.user.person.defaultCoordinate is not null %}
<iframe
src="https://ticket-feedback-form.phpr.link/{{ locale }}/feedback"
frameborder="0"
allowfullscreen
id="frame1"
loading="lazy"
onload="sendInformationsToiFrame(this, '{{ app.user.person.firstName }}', '{{ app.user.person.lastName }}', '{{ app.user.person.defaultCoordinate.contactsEmail }}', '{{ app.user.person.defaultCoordinate.contactsTel }}')"
>
</iframe>
{% elseif app.user.username == 'admin' or app.user.username == 'phpc' %}
<iframe
id="frame1"
src="https://ticket-feedback-form.phpr.link/{{ locale }}/feedback"
loading="lazy"
frameborder="0"
allowfullscreen
onload="sendInformationsToiFrame(this, 'Mr', 'Administrator', 'support@phpcreation.com', '0000-000-000')"
>
</iframe>
{% else %}
<iframe
id="frame1"
src="https://ticket-feedback-form.phpr.link/{{ locale }}/feedback"
loading="lazy"
frameborder="0"
allowfullscreen
onload="sendInformationsToiFrame(this)"
>
</iframe>
{% endif %}
</div>
</div>
<script>
var modalLink = document.querySelector(".open-modal");
var modalContainer = document.getElementById("iframeContainer");
var closeBtn = document.getElementById("closeBtn");
var iframe = document.getElementById("frame");
function openModal() {
modalContainer.style.display = "flex";
}
function closeModal() {
modalContainer.style.display = "none";
}
modalLink.addEventListener("click", function (event) {
event.preventDefault();
openModal();
});
closeBtn.addEventListener("click", function (event) {
closeModal();
});
var iframeLinks = document.querySelectorAll(".iframe-link");
iframeLinks.forEach(function (link) {
link.style.display = "inline";
});
</script>
{# Ticket feedback JS #}
{# Needs html2canvas for screenshots #}
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
{# Should be PHPC CDN + fallback local #}
<script src="https://ticket-feedback-form.phpr.link/assets/js/new/sendAllInformationsToiFrame.js"></script>
Add the "Report a problem" link
Example of a report a problem link from PHPR:
<a href="https://ticket-feedback-form.phpr.link/fr/feedback" class="iframe-link open-modal">{{ 'signalProblem'|trans }} <span class="glyphicons glyphicons-bug"></span></a>
Add the link to the feedback in the href as a fallback if the user has JS disabled for some reason.
Final step
Test the integration. The feedback should work correctly, redefine some css if necessary.
Post Message:
1. If you want to send basic data to the ticket you can use the JS function and send it through onload.
Use this script tag:
<script src="https://dev.ticket-feedback-form.phpr.link/assets/js/new/sendInformationsToiFrame.js"></script>
How to send data:
<iframe
id="frame"
src="https://dev.ticket-feedback-form.phpr.link/feedback"
frameborder="0"
allowfullscreen
onload="sendInformationsToiFrame(this, 'Hadi', 'Haider', 'support@phpcreation.com', '(450) 305-6253', 'This is a dev note', 'Test description from demo!', true, 'This is a reproduction note')"
></iframe>
sendInformationsToiFrame
function will take these inputs:
- Frame (this)
- First Name
- Last Name
- Email Address
- Phone Number
- Dev Note
- Client Demand
- Client Urgency
- Reproduction Note
2. Send a Screenshot of the page only.
Use this script tag:
<script src="https://dev.ticket-feedback-form.phpr.link/assets/js/new/sendScreenShotToiFrame.js"></script>
How to send data:
<iframe
id="frame"
src="https://dev.ticket-feedback-form.phpr.link/feedback"
frameborder="0"
allowfullscreen
onload="sendScreenShotToiFrame(this)"
></iframe>
3. Send a Form Urgency Status of the page only.
Use this script tag:
<script src="https://dev.ticket-feedback-form.phpr.link/assets/js/new/sendUrgencyStatusToiFrame.js"></script>
How to send data:
<iframe
id="frame"
src="https://dev.ticket-feedback-form.phpr.link/feedback"
frameborder="0"
allowfullscreen
onload="sendUrgencyStatusToiFrame(this, true)"
>
</iframe>
Query Params:
There are a few query parameters used to fill the input fields directly.
- First Name ->
https://dev.ticket-feedback-form.phpr.link/feedback?firstName=Simon
- Last Name ->
https://dev.ticket-feedback-form.phpr.link/feedback?lastName=Tremblay
- Email ->
https://dev.ticket-feedback-form.phpr.link/feedback?email=phpc@phpcreation.com
- Phone ->
https://dev.ticket-feedback-form.phpr.link/feedback?phone=32189392011
- Description ->
https://dev.ticket-feedback-form.phpr.link/en/feedback?clientDemand=Test%20Description%20from%20Demo
- Urgency ->
https://dev.ticket-feedback-form.phpr.link/feedback?urgency=true
- URL ->
https://dev.ticket-feedback-form.phpr.link/en/feedback?url=https://phpcreation.com
Send all parameters at once by separating them with &
https://dev.ticket-feedback-form.phpr.link/feedback?firstName=Simon&lastName=Tremblay&email=phpc@phpcreation.com&phone=32189392011&clientDemand=Test%20Description%20from%20Demo&urgency=true&url=https://phpcreation.com
What is the purpose of Keep contact details?
This switch button will be true
by default however, you can update this. The purpose of this option is to make it easy for user to use the form again. The basic details will get saved into browser's localstorage
and will be refetched again when ticket feedback is used. You can update the fields if the fields are already filled.
How to submit form?
Fill out the form details and click on Send
button or press Enter
key on your keyboard.
If don't fill out any of these fields and try to submit the form you will see these errors.
Emergency:
Click on this Alert
button on the header.
This button will turn into Red
and other fields too. The button text will change into Emergency
and will have Red
color.
Confirmation Page:
Features:
- Create New Ticket by clicking on the button
Create New Ticket
- Preview Ticket Followup page
Followup Page:
Features:
- Close Ticket
- Create New Ticket
- Add a QA Note for Admins
- If you're an admin you can view this ticket on
Ticket CRUD Project
Environments:
dev:
Corresponds to development environment and GitHub CICD branch is main
staging:
Corresponds to staging environment and GitHub CICD branch is staging
prod:
Corresponds to production environment and GitHub CICD branch is production
References:
Dev link : https://dev.ticket-feedback-form.phpr.link/ (opens in a new tab)
Github URL : https://github.com/PHPCreation/ticket-client-feedback-react-nextjs (opens in a new tab)