first commit

This commit is contained in:
dwindown
2025-08-21 20:39:34 +07:00
commit 58c1497171
576 changed files with 177044 additions and 0 deletions

BIN
admin/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,3 @@
.table-toolbar {
justify-content: flex-end;
}

View File

@@ -0,0 +1,267 @@
input.formipay-post-shortcode-input {
padding: 0.5em;
background-color: #efefef;
color: #2c3338;
border: 1px solid #2c3338;
border-radius: .5em;
}
.pointer {
cursor: pointer;
}
#titlediv #title-prompt-text {
padding: 3px 10px;
}
.editor-styles-wrapper h1 {
font-size: 24px!important;
margin: unset!important;
width: 100%;
max-width: 100%!important;
border: 1px solid #ccc;
padding: .25rem 1rem;
border-radius: .5rem;
}
#sidebar_panel {
background-color: #2c3e50;
flex: 0 0 273px;
}
#fields_panel {
background-color: #f0f3f5;
flex: 1 1 calc(100% - 273px);
}
#preview-wrapper {
border: 3px dashed #ccc;
padding: 1.8rem 1rem;
max-width: 500px;
margin: auto;
border-radius: 1rem
}
#add_field_form {
position: sticky;
top: 140px;
}
#add_field_form input[type=text],
#add_field_form select,
div#preview-wrapper input:not([type=checkbox],[type=radio]),
div#preview-wrapper select {
border-radius: 5px;
border: 1px solid #bec5cb;
background-color: #ffffff;
height: 40px;
padding: 6px 16px;
line-height: 1.4em;
}
.label-divider, .label-page_break {
font-size: larger;
font-weight: bold;
}
span.divider-line {
border-top: 1px dashed #ccc;
display: block;
}
.preview-field{
position: relative;
}
[data-field-type="page_break"] {
border-top: 2px dashed #a3a3a3;
padding-top: .5em;
}
span.grab {
cursor: grab;
}
.the_buttons > button {
padding: .15rem!important;
}
.the_buttons svg {
margin-bottom: 1px;
}
#preview-wrapper .the_buttons svg path {
fill: #ccc!important;
stroke: #ccc!important;
}
.the_buttons > button svg {
margin-bottom: 1px;
}
#preview-wrapper .the_buttons > button:hover svg path {
fill: #666!important;
stroke: #666!important;
}
span.scissors {
position: absolute;
display: inline-block;
top: -10px;
}
.field-icons.the_buttons button {
border: 1px solid #ccc;
border-radius: 50%;
color: #ccc!important;
margin-bottom: .5em;
}
.field-icons.the_buttons button:hover {
border: 1px solid #666;
border-radius: 50%;
color: #666!important;
margin-bottom: .5em;
background-color: #ffffff;
}
.field-icons i {
color: #666;
cursor: pointer;
}
.field-icons i:hover {
color: #555;
}
.form-check.form-switch {
display: flex;
align-items: center;
}
.form-switch .form-check-input {
background-repeat: no-repeat;
}
.wp-core-ui.wp-editor-wrap {
margin-top: -2.5em;
}
.form-check.formipay-radio-group {
display: flex;
align-items: center;
gap: .5em;
}
.form-check.formipay-radio-group > input::before {
background-color: white;
}
.stm_metaboxes_grid__inner #appearance {
padding-right: 0!important;
}
.stm_metaboxes_grid__inner #appearance .row {
margin-left: 0!important;
}
.stm_metaboxes_grid__inner #appearance .column {
padding: 1.8rem!important;
}
.wpcfto-tab.active {
padding-right: 0!important;
}
.wpcfto-tab.active > .container > .row {
margin: 0!important;
}
.wpcfto-repeater-single:not(:first-child) {
border-top: 1px solid #ccc!important;
}
.wpcfto_settings_head+.stm_metaboxes_grid .stm_metaboxes_grid__inner .row .column {
padding-right: 1.8rem!important;
}
.wpcfto_group_started .wpcfto_generic_field_editor {
padding: 0!important;
}
#formipay .inside, #formipay_canvas .inside {
padding: 0!important;
margin: 0!important;
}
#payments .wpcfto-field-content .wpcfto_multi_checkbox {
display: flex;
flex-direction: column;
}
#payments .wpcfto-field-content .wpcfto_multi_checkbox > label {
width: 100%;
}
.formipay-checkbox-wrapper {
display: grid;
}
.trumbowyg-textarea {
min-height: 14em !important;
height: unset!important;
}
.wpcfto-editor span.ql-formats:nth-last-child(3) {
display: none!important;
}
.stm_metaboxes_grid__inner, .wpcfto_settings_head {
max-width: unset!important;
}
.wpcfto-box-child.repeater {
padding-top: 0;
padding-right: calc(var(--bs-gutter-x) * .5);
padding-left: calc(var(--bs-gutter-x) * .5);
padding-bottom: 0;
}
#inactive.wpcfto_sorter_single > h6 {
background-color: #999999;
}
.dropzone {
border: 2px dashed #0073aa;
border-radius: 5px;
padding: 20px;
text-align: center;
transition: background-color 0.3s;
margin-bottom: 20px;
}
.dropzone-area {
cursor: pointer;
}
.dropzone-area:hover {
background-color: #f0f8ff;
}
#thumbnailPreview {
margin-top: 10px;
}
#previewImage {
max-width: 100%;
height: auto;
margin-top: 10px;
}
#uploadStatus {
font-size: 16px;
color: #333;
}
.child-field-title {
border-radius: 10px;
}
.child-field-title.option-detail-opened {
border-radius: 10px 10px 0 0;
}
.child-field-wrapper {
border-top: unset;
background-color: #666;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
.table>:not(caption)>*>* {
background-color: unset!important;
vertical-align: middle;
}
.table.child-field-input-table tr:last-child th,
.table.child-field-input-table tr:last-child td {
border-bottom: unset!important;
}
.child-field-image-wrapper {
border: 4px dashed #cccccc;
padding: 10px;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: .5em;
border-radius: 10px;
}
.the_buttons button {
font-size: 10px;
width: 24px;
height: 24px;
border-radius: 50%;
}
.child-fields-wrapper table th {
vertical-align: top;
}
.trumbowyg-modal.trumbowyg-fixed-top {
display: none;
}
.top-40 {
top: 40px!important;
}
.sortable {
touch-action: none;
}

View File

@@ -0,0 +1,52 @@
li#toplevel_page_formipay .wp-menu-image img {
width: 18px;
}
li#toplevel_page_formipay a[href^="admin.php?page=formipay-orders"]:before,
li#toplevel_page_formipay a[href^="admin.php?page=formipay-settings"]:before{
border-bottom: 1px solid hsla(0, 0%, 100%, .2);
display: block;
float: left;
margin: 8px -15px 13px;
content: "";
width: calc(100% + 26px);
}
/** CHOICES */
.category > .choices {
min-width: 200px;
}
.choices__inner {
max-width: 100%;
width: unset;
display: block;
min-height: unset!important;
padding: 2px!important;
border: 1px solid #b7b7b7!important;
border-radius: .5em!important;
background-color: #ffffff;
}
.choices__list {
display: block;
}
.choices__list:not(.choices__list--dropdown) {
padding: 10px 14px;
}
.choices__list.choices__list--dropdown {
margin-top: .5em;
border-radius: .5em;
}
.choices__list.choices__list--dropdown > .choices__list {
padding: 0;
}
.choices__item.choices__item--choice.is-selected.choices__item--selectable.is-highlighted {
background-color: #277aff25!important;
}
/** END CHOICES */
.wp-submenu-wrap li:has(a[href="edit-tags.php?taxonomy=formipay-product-category&post_type=formipay-product"]) {
display: none;
}
.wp-submenu-wrap li:has(a[href="admin.php?page=formipay-products"]).current ~ li:has(a[href="edit-tags.php?taxonomy=formipay-product-category&post_type=formipay-product"]),
.wp-submenu-wrap li:has(a[href="admin.php?page=formipay-products"]):hover ~ li:has(a[href="edit-tags.php?taxonomy=formipay-product-category&post_type=formipay-product"]),
.wp-submenu-wrap li:has(a[href="edit-tags.php?taxonomy=formipay-product-category&post_type=formipay-product"]).current {
display: block;
}

View File

@@ -0,0 +1,93 @@
table#order-items-table th {
width: 60%;
}
table#order-items-table td {
width: 40%;
text-align: right
}
table#order-items-table #order-total {
color: #277aff!important;
font-size: larger;
font-weight: bold
}
.card {
max-width: unset!important;
}
.card-header {
font-size: 17px;
font-weight: bold;
}
b.field-name {
text-transform: capitalize;
font-size: smaller;
}
.media, .recipient-type, .notification-status {
text-transform: capitalize;
}
/** Timeline Trx Tracking **/
.rb-container {
width: 50%;
display: block;
position: relative;
}
.rb-container ul.rb {
margin: 2.5em 0 0;
padding: 0;
display: block;
}
.rb-container ul.rb li {
list-style: none;
margin: auto;
min-height: 50px;
border-left: 1px dashed #000;
padding: 0 0 50px 30px;
position: relative;
}
.rb-container ul.rb li:last-child {
border-left: 0;
}
.rb-container ul.rb li::before {
position: absolute;
left: -10px;
top: 0;
content: " ";
border: 10px solid rgba(0, 0, 0, 1);
border-radius: 500%;
background: #277aff;
height: 20px;
width: 20px;
transition: all 500ms ease-in-out;
}
.rb-container ul.rb li:hover::before {
border-width: 0;
}
ul.rb li .timestamp {
color: #277aff;
position: relative;
font-size: smaller;
}
input, select, .form-control, .form-select {
height: 40px;
}
#order_status {
width: 200px;
}
.access-link-wrapper {
display: flex!important;
}
.access-link-wrapper > input {
flex: 0 0 calc(100% - 100px)!important;
}
.access-link-wrapper > button {
flex: 0 0 100px!important;
}
.top-40 {
top: 40px!important;
}

View File

@@ -0,0 +1,43 @@
#formipay-orders table td {
vertical-align: top;
}
th.gridjs-th[data-column-id=id],
th.gridjs-th[data-column-id=date],
th.gridjs-th[data-column-id=total],
th.gridjs-th[data-column-id=paymentGateway],
th.gridjs-th[data-column-id=status] {
text-align: center;
}
td.gridjs-td[data-column-id=id],
td.gridjs-td[data-column-id=paymentGateway],
td.gridjs-td[data-column-id=date],
td.gridjs-td[data-column-id=status] {
text-align: center;
}
span.grand_total {
display: flex;
justify-content: space-between;
align-items: center;
}
span.grand_total img {
margin-bottom: -4px;
}
span:has(.status-label) {
width: 100%;
display: block;
text-align: center;
padding-top: 5px;
}
span.status-label {
padding: 5px 10px;
border-radius: 5px;
text-transform: capitalize;
background-color: #999999;
color: white;
}
span.status-label.Completed {
background-color: #277aff;
}
.top-40 {
top: 40px!important;
}

View File

@@ -0,0 +1,217 @@
body {
background-color: #f0f0f1!important;
}
#screen-meta-links:not(:has(button.screen-meta-active)), #screen-meta {
margin-top: -2em;
}
/** Header **/
div#wpbody-content {
position: relative;
}
.formipay-screen-menu {
margin-left: -20px;
margin-bottom: 2em;
padding: 10px 20px 10px 50px;
background-color: white;
display: flex;
gap: 1em;
align-items: center;
position: sticky;
top: 32px;
left: 0;
z-index: 999;
box-shadow: 0 10px 20px #d2d2d2
}
.formipay-screen-menu h1 {
font-size: 24px!important;
color: #1d2327;
margin: .67em 0;
}
.screen-title {
display: flex;
align-items: center;
gap: 1em;
}
.formipay-screen-menu > img {
width: 56px;
}
/** END Header **/
/** Metabox */
.stm_metaboxes_grid__inner .wpcfto-tab {
padding: 0!important;
}
.stm_metaboxes_grid__inner #appearance {
padding-right: 0!important;
}
.stm_metaboxes_grid__inner #appearance .row {
margin-left: 0!important;
}
.stm_metaboxes_grid__inner #appearance .column {
padding: 1.8rem!important;
}
.wpcfto-tab.active {
padding-right: 0!important;
}
.wpcfto-tab.active > .container > .row {
margin: 0!important;
}
.wpcfto-repeater-single:not(:first-child) {
border-top: 1px solid #ccc!important;
}
.wpcfto_settings_head+.stm_metaboxes_grid .stm_metaboxes_grid__inner .row .column {
padding-right: 1.8rem!important;
}
.wpcfto_group_started .wpcfto_generic_field_editor {
padding: 0!important;
}
.trumbowyg-textarea {
min-height: 14em !important;
height: unset!important;
}
.wpcfto-editor span.ql-formats:nth-last-child(3) {
display: none!important;
}
.stm_metaboxes_grid__inner, .wpcfto_settings_head {
max-width: unset!important;
}
.wpcfto-box-child.repeater {
padding-top: 0;
padding-right: calc(var(--bs-gutter-x) * .5);
padding-left: calc(var(--bs-gutter-x) * .5);
padding-bottom: 0;
}
#inactive.wpcfto_sorter_single > h6 {
background-color: #999999;
}
.wpcfto_sorter .list-group-item.disable {
color: #8c99a5;
background-color: #efefef;
}
.wpcfto_sorter .list-group-item.disable:hover {
color: #f72657;
}
.wpcfto_sorter .list-group-item i {
float: right;
margin-top: 2px;
}
.choices {
overflow: visible!important;
margin-right: .5rem;
}
/** Table **/
.post-action a {
text-decoration: none;
}
button#formipay-delete-selected {
min-height: 44px;
margin-bottom: 0!important;
border-radius: .5rem;
color: #58151c;
font-size: 16px;
padding: 5px 10px;
text-decoration: none;
border-radius: .5em;
border: 1px solid #58151c;
background-color: #f1aeb5;
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
}
.table-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 1em;
}
.post-status-wrapper {
display: flex;
gap: .5rem;
align-items: center;
}
.post-status-wrapper a {
color: #999999;
cursor: pointer;
}
.post-status-wrapper a[data-active=true] {
color: #277aff;
font-weight: bold;
}
table.gridjs-table th, button.gridjs-currentPage {
background: #277aff!important;
color: #ffffff;
}
table.gridjs-table tr *:is(th, td):first-child {
padding-left: 1rem;
padding-right: 1rem;
}
.gridjs-pagination button:hover {
background-color: #277aff!important;
color: white!important;
}
.gridjs-head {
display: none;
}
#reset-filter {
color: #277aff;
font-weight: bold;
cursor: pointer;
}
.filter-bar {
display: flex;
gap: .5em;
justify-content: flex-end;
align-items: center;
}
.filter-bar select, .filter-bar input{
padding: .5em 1em;
border-radius: .5em;
color: #666666 !important;
border: 1px solid #b7b7b7 !important;
min-height: 44px !important;
}
.filter-bar select {
padding-right: 1.75em;
}
.gridjs-pages > * {
padding: 1em 1.5em!important;
}
/** END Table **/
/** SweetAlert2 **/
button.swal2-confirm.swal2-styled {
background-color: rgb(39, 122, 255)!important;
}
div:where(.swal2-container) button:where(.swal2-styled).swal2-confirm:focus {
box-shadow: 0 0 0 3px rgba(39, 122, 255, .5)!important;
}
.top-40 {
top: 40px!important;
}
/** END SweetAlert2 **/
@media screen and (max-width: 767px) {
.formipay-screen-menu {
top: 0;
align-items: start;
}
.screen-title h1 {
flex: 0 0 100%;
}
.screen-title {
flex-wrap: wrap;
}
.filter-bar {
flex-direction: column;
align-items: start;
}
.filter-bar,
.filter-bar > *:not(:first-child),
.filter-bar > *:not(:first-child) > * {
width: 100%;
}
}

View File

@@ -0,0 +1,140 @@
#product-variables-table {
padding: 0;
}
#product-variables-table > .wpcfto-field-content {
width: 100%;
}
#product-variables-table > .wpcfto-field-content > table.wpcfto-table {
width:100%;
margin-bottom:1em;
}
#product-variables-table > .wpcfto-field-content > table.wpcfto-table th {
vertical-align: bottom;
}
th[data-cell="name"] {
text-align: left!important;
}
th[data-cell="price"], td[data-cell="price"],
th[data-cell="sale"], td[data-cell="sale"] {
max-width: 150px;
}
th[data-cell="stock"], td[data-cell="stock"],
th[data-cell="weight"], td[data-cell="weight"] {
max-width: 100px;
}
/* Toggle Switch Styles */
.switch {
position: relative;
display: inline-block;
width: 36px;
height: 20px;
vertical-align: middle;
}
.switch input { display:none; }
.slider {
position: absolute;
cursor: pointer;
background-color: #ccc;
border-radius: 20px;
top: 0; left: 0; right: 0; bottom: 0;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 16px; width: 16px;
left: 2px; bottom: 2px;
background-color: white;
border-radius: 50%;
transition: .4s;
}
input:checked + .slider {
background-color: #2985f7;
}
input:checked + .slider:before {
transform: translateX(16px);
}
/* Gray out inactive rows */
.variation-inactive {
background: #eee !important;
opacity: 0.7;
}
.price-input-wrapper {
display: flex;
align-items: center;
border: 1px solid #ccc;
border-radius: 4px;
overflow: hidden;
}
.price-input-wrapper span {
background: #eee;
padding: 0 8px;
border-right: 1px solid #ccc;
user-select: none;
white-space: nowrap;
height: 40px;
display: flex;
align-items: center;
}
.price-input-wrapper input {
border: none!important;
outline: none;
padding: 6px 8px!important;
flex: 1;
text-align: right;
}
.button-link.child-row-toggle {
transition: all .5s ease-out;
}
.button-link.child-row-toggle:active,
.button-link.child-row-toggle:focus {
box-shadow: unset!important;
}
.button-link.child-row-toggle.active {
transform: rotate(180deg);
}
td.manual-price-hint {
color: #8c99a5;
text-align: center;
cursor: pointer;
}
.variation-details-content {
padding: 1rem;
border: 1px dashed #bec5cb;
border-radius: 1rem;
margin-bottom: 1rem;
}
.price-input-wrapper > .price-currency {
min-width: 40px;
justify-content: center;
}
table.wpcfto-table.inner-table {
width: 100%;
border-collapse:collapse
}
table.wpcfto-table.inner-table tr > th {
text-transform: uppercase;
background-color: #bec5cb;
padding: 5px;
font-size: 12px;
}
table.wpcfto-table.inner-table tr td {
padding: 5px 0 5px 5px;
}
table.wpcfto-table.inner-table tbody tr:hover td {
background-color: #dfe7ee;
}
table.wpcfto-table.inner-table tr > *:is(th, td):first-child {
width: 50%;
text-align: left;
}

View File

@@ -0,0 +1,16 @@
.nav-link.active:hover {
color: white;
}
.form-check.form-switch {
display: flex;
align-items: center;
}
.form-switch .form-check-input {
background-repeat: no-repeat;
}
.formipay-editor-tab-content .card {
max-width: unset;
}
.top-40 {
top: 40px!important;
}

View File

@@ -0,0 +1,155 @@
.wp-header-end {
margin: 30px 0 0;
}
/* === Title Input Box === */
#title {
font-size: 1.5rem!important;
padding: 16px!important;
border-radius: 8px;
border: unset;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
margin-bottom: 15px!important;
height: unset!important;
}
/* === Meta Boxes General Styling === */
.postbox {
background-color: #fff;
border: none;
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0,0,0,0.1);
padding: 15px;
margin-bottom: 20px;
}
.postbox h2.hndle {
font-size: 1.1rem!important;
padding: 10px 15px 10px 0!important;
border-radius: 6px 6px 0 0;
cursor: pointer!important;
}
/* === Publish Box (Right Side) === */
#submitdiv {
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0,0,0,0.1);
background-color: #f9f9f9;
}
#submitdiv h3 {
background-color: #f1f1f1;
padding: 10px 15px;
font-size: 1rem;
}
#submitdiv .inside {
padding: 15px;
}
#publishing-action {
display: flex;
justify-content: space-between;
align-items: center;
}
#publishing-action input[type="submit"] {
font-size: 1rem;
padding: 10px 25px;
border-radius: 6px;
border: none;
background-color: #0073aa;
color: #fff;
cursor: pointer;
}
#major-publishing-actions {
align-items: center;
display: flex;
justify-content: space-between;
padding: 10px 0;
flex-direction: column-reverse;
gap: 1rem;
}
#major-publishing-actions > *,
#major-publishing-actions > * > * {
width: 100%;
position: relative;
text-align: center;
}
#major-publishing-actions .spinner {
position: absolute;
z-index: 9;
background: unset;
margin: unset;
display: unset;
}
a#post-preview {
width: 100%;
padding: 5px 15px;
border-radius: 6px;
}
#minor-publishing-actions {
margin-bottom: 10px;
}
/* === Categories / Tags Boxes === */
#categorydiv,
#tagsdiv-post_tag {
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0,0,0,0.1);
background-color: #fff;
}
#categorydiv h3,
#tagsdiv-post_tag h3 {
background-color: #f5f5f5;
padding: 10px 15px;
font-size: 1rem;
}
#categorychecklist li label,
#tagchecklist span a {
font-size: 0.95rem;
}
#tag-input {
border-radius: 6px;
padding: 6px 10px;
font-size: 0.95rem;
}
.inside:has(.categorydiv) {
padding: 0;
}
ul.category-tabs li.tabs, input#formipay-product-category-add-submit {
border: 1px solid #0073aa;
background-color: white;
border-radius: 5px;
padding: 8px 15px;
}
ul.category-tabs li.tabs a{
color: #0073aa!important;
outline: unset;
border: unset;
box-shadow: unset;
}
ul.category-tabs li.tabs a:focus,
ul.category-tabs li.tabs a:active {
outline: unset;
border: unset;
box-shadow: unset;
}
.categorydiv .tabs-panel {
border: unset!important;
}
/* === WYSIWYG Editor (TinyMCE) === */
.mce-container {
border-radius: 8px !important;
overflow: hidden;
}
.mce-toolbar-grp {
background-color: #f5f5f5 !important;
border-bottom: 1px solid #ddd !important;
}

View File

@@ -0,0 +1,30 @@
.formipay-label {
width: 100%;
font-weight: bold;
font-size: smaller;
margin-bottom: 3px
}
.formipay-input {
width: 100%;
padding-right: 1em!important;
padding-left: 1em!important;
}
.formipay-input:not([type=radio]):not([type=checkbox]){
min-height: 30px;
}
.formipay-select {
width: 100%;
height: 30px;
padding-right: 1em!important;
padding-left: 1em!important;
}
.formipay-inline-desc {
font-size: 12px;
color: #666666;
}
.repeater-child-input:first-child .delete-option {
display: none;
}
.top-40 {
top: 40px!important;
}

View File

@@ -0,0 +1,31 @@
.stm_metaboxes_grid__inner, .wpcfto_settings_head {
max-width: 100%!important;
}
.wpcfto-settings[data-vue=formipay_settings] .wpcfto-field-aside {
width: 25%;
}
.wpcfto-settings[data-vue=formipay_settings] .wpcfto-field-content {
width: 75%;
}
.wpcfto-repeater-single:not(:first-child) {
border-top: 1px solid #ccc!important;
}
.paypal-instruction-point {
list-style: auto;
}
.global-paypal-instruction ul:not(.paypal-instruction-point) {
list-style: disc;
}
.global-paypal-instruction > h5 {
font-size: 16px!important;
font-weight: bold;
}
.global-paypal-instruction b {
font-weight: bold;
}
.global-paypal-instruction ul {
padding-left: 2rem;
}
.top-40 {
top: 40px!important;
}

View File

@@ -0,0 +1,61 @@
#formipay-access-items table td {
vertical-align: top;
}
a#add-new-item {
color: #277aff;
font-size: 16px;
padding: 5px 10px;
text-decoration: none;
border-radius: 5px;
border: 1px solid #277aff;
}
a#add-new-item:hover {
color: #ffffff;
background-color: #277aff;
}
th.gridjs-th[data-column-id=id],
th.gridjs-th[data-column-id=type],
th.gridjs-th[data-column-id=status] {
text-align: center;
}
td.gridjs-td[data-column-id=id],
td.gridjs-td[data-column-id=type],
td.gridjs-td[data-column-id=status] {
text-align: center;
}
td.gridjs-td[data-column-id=productRelation] > span {
display: flex;
gap: .5em;
flex-wrap: wrap;
}
div#formipay-access-items td svg {
margin-right: .25em;
margin-bottom: -4px;
}
.product_related {
background-color: #dedede;
padding: 5px 7px;
border-radius: 5px;
}
span:has(.status-label) {
width: 100%;
display: block;
text-align: center;
padding-top: 5px;
}
span.status-label {
padding: 5px 10px;
border-radius: 5px;
text-transform: capitalize;
}
span.status-label.publish {
background-color: #277aff;
color: white;
}
span.status-label.draft {
background-color: #999999;
color: white;
}
.top-40 {
top: 40px!important;
}

View File

@@ -0,0 +1,75 @@
#formipay-coupons table td {
vertical-align: top;
}
a#add-new-coupon {
color: #277aff;
font-size: 16px;
padding: 5px 10px;
text-decoration: none;
border-radius: 5px;
border: 1px solid #277aff;
}
a#add-new-coupon:hover {
color: #ffffff;
background-color: #277aff;
}
.formipay-form-shortcode {
padding: .5em;
border-radius: .5em;
color: #666666!important;
border: 1px solid #b7b7b7!important;
}
td.gridjs-td[data-column-id=productRelation] > span {
display: flex;
gap: .5em;
flex-wrap: wrap;
}
.product_related {
background-color: #dedede;
padding: 5px 7px;
border-radius: 5px;
}
span.product_related img {
margin-bottom: -3px;
}
th.gridjs-th[data-column-id=id],
th.gridjs-th[data-column-id=usages],
th.gridjs-th[data-column-id=type],
th.gridjs-th[data-column-id=dateLimit],
th.gridjs-th[data-column-id=status] {
text-align: center;
}
td.gridjs-td[data-column-id=id],
td.gridjs-td[data-column-id=usages],
td.gridjs-td[data-column-id=type],
td.gridjs-td[data-column-id=dateLimit] {
text-align: center;
}
th.gridjs-th[data-column-id=amount],
td.gridjs-td[data-column-id=amount] {
text-align: right;
}
span:has(.status-label) {
width: 100%;
display: block;
text-align: center;
padding-top: 5px;
}
span.status-label {
padding: 5px 10px;
border-radius: 5px;
}
span.status-label.active {
background-color: #277aff;
color: white;
}
span.status-label.inactive {
background-color: #999999;
color: white;
}
.top-40 {
top: 40px!important;
}

View File

@@ -0,0 +1,77 @@
#formipay-forms table td {
vertical-align: top;
}
.formipay-screen-menu a {
color: #277aff;
font-size: 16px;
padding: 5px 10px;
text-decoration: none;
border-radius: 5px;
border: 1px solid #277aff;
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
}
.formipay-screen-menu a:hover {
color: #ffffff;
background-color: #277aff;
}
.formipay-form-shortcode {
padding: .5em;
border-radius: .5em;
color: #666666!important;
border: 1px solid #b7b7b7!important;
}
th.gridjs-th[data-column-id=id], th.gridjs-th[data-column-id=date], th.gridjs-th[data-column-id=status],
td.gridjs-td[data-column-id=id], td.gridjs-td[data-column-id=date], td.gridjs-td[data-column-id=status] {
text-align: center;
}
.gridjs-pages > * {
padding: 1em 1.5em!important;
}
span:has(.formipay-form-shortcode){
display: flex;
gap: 5px;
max-width: 100%;
flex-wrap: nowrap
}
.formipay-form-shortcode {
flex: 0 1 200px;
width: unset!important;
max-width: unset!important;
min-width: unset!important;
}
button.copy-shortcode {
border: 1px solid #b7b7b7;
height: 32px;
padding: 5px;
border-radius: 5px;
cursor: pointer;
}
button.copy-shortcode svg {
margin-bottom: -4px;
}
span:has(.status-label) {
width: 100%;
display: block;
text-align: center;
padding-top: 5px;
}
span.status-label {
padding: 5px 10px;
border-radius: 5px;
text-transform: capitalize;
}
span.status-label.publish {
background-color: #277aff;
color: white;
}
span.status-label.draft {
background-color: #999999;
color: white;
}
.top-40 {
top: 40px!important;
}

View File

@@ -0,0 +1,91 @@
.tablenav.top:has(.no-pages) {
display: none;
}
#col-container {
margin-top: 3em;
}
div#col-left {
background-color: white;
border-radius: 8px;
}
div#col-left .form-wrap {
padding: 1em
}
div#col-left input, div#col-left select, div#col-left textarea {
max-width: none;
width: 100%!important;
}
#col-right .col-wrap {
padding-left: 1em
}
input, textarea{
padding: .5em 1em!important;
border-radius: .5em!important;
color: #666666 !important;
border: 1px solid #b7b7b7 !important;
}
select {
padding: .5em 1.5em .5em 1em!important;
border-radius: .5em!important;
color: #666666 !important;
border: 1px solid #b7b7b7 !important;
}
thead > tr > * {
padding: 1em !important;
background: #277aff!important;
color: #ffffff;
border: 1px solid #e5e7eb;
box-sizing: content-box;
}
tfoot > tr > * {
padding: 1em!important;
border: 1px solid #e5e7eb;
box-sizing: content-box;
}
td, tbody > tr > *:first-child {
padding: .5em 1em!important;
border: 1px solid #e5e7eb;
box-sizing: content-box;
}
th a {
padding: 0!important;
}
thead a {
color: white!important;
}
td a{
padding: 0!important;
}
table {
margin-top: 1.25em!important;
border-radius: 8px!important;
border-collapse: collapse;
}
.tablenav.top {
display: flex;
align-items: center;
justify-content: space-between;
}
.tablenav.top > .tablenav-pages {
display: none;
}
table > thead {
border-radius: 8px 8px 0 0!important;
}
table > thead > tr > *:first-child {
border-top-left-radius: 8px!important;
}
table > thead > tr > *:last-child {
border-top-right-radius: 8px!important;
}
thead th.sorted span.sorting-indicator.asc::before {
color: white!important;
}
input#submit {
background: #277aff!important;
color: #ffffff!important;
border: unset!important;
}
.top-40 {
top: 40px!important;
}

View File

@@ -0,0 +1,96 @@
#formipay-forms table td {
vertical-align: top;
}
.formipay-screen-menu a {
color: #277aff;
font-size: 16px;
padding: 5px 10px;
text-decoration: none;
border-radius: 5px;
border: 1px solid #277aff;
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
}
.formipay-screen-menu a:hover {
color: #ffffff;
background-color: #277aff;
}
/** Table **/
td.gridjs-td[data-column-id=price] .price {
text-wrap: nowrap;
display: flex;
align-items: center;
gap: .5em;
justify-content: space-between;
}
th.gridjs-th[data-column-id=id],
th.gridjs-th[data-column-id=type],
th.gridjs-th[data-column-id=price],
th.gridjs-th[data-column-id=stock],
th.gridjs-th[data-column-id=status] {
text-align: center;
}
td.gridjs-td[data-column-id=id],
td.gridjs-td[data-column-id=type],
td.gridjs-td[data-column-id=price],
td.gridjs-td[data-column-id=stock],
td.gridjs-td[data-column-id=status] {
text-align: center;
}
.gridjs-pages > * {
padding: 1em 1.5em!important;
}
span:has(.status-label) {
width: 100%;
display: block;
text-align: center;
padding-top: 5px;
}
span.status-label {
padding: 5px 10px;
border-radius: 5px;
text-transform: capitalize;
}
span.status-label.publish {
background-color: #277aff;
color: white;
}
span.status-label.draft {
background-color: #999999;
color: white;
}
.top-40 {
top: 40px!important;
}
/** SWAL new Product **/
div#swal2-html-container table th {
width: 45%;
}
div#swal2-html-container table td {
width: 55%;
}
#swal2-html-container input {
border: 1px solid #b7b7b7 !important;
border-radius: .5em !important;
}
#swal2-html-container input:not(type="checkbox"):not(type="radio"){
height: 34px!important;
padding: 10px 14px!important;
width: 100%!important;
max-width: unset!important;
margin: unset!important;
}
#swal2-html-container *:is(th, td) > * {
margin: unset!important;
text-align: left;
}
#swal2-html-container *:is(th, td){
height: 40px;
}
#swal2-html-container tr:not(:last-child) *:is(th, td) {
border-bottom: 1px solid #b7b7b7;
}

BIN
admin/assets/img/White.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@@ -0,0 +1,14 @@
jQuery(function($){
$('#wpbody-content').prepend(`
<div class="formipay-screen-menu">
<img src="`+formipay_admin.site_url+`/wp-content/plugins/formipay/admin/assets/img/formipay-logo-circle-white_256.png" alt="Formipay">
<div class="screen-title">
<h1>`+formipay_admin.page_title+`</h1>
</div>
</div>
`);
$('form.search-form.wp-clearfix').appendTo('.tablenav.top');
$('.wp-heading-inline, .page-title-action').hide();
});

View File

@@ -0,0 +1,78 @@
jQuery(function($){
let formipay_table_grid = new gridjs.Grid({
server: {
url: formipay_customers_page.ajax_url+'?action=formipay-tabledata-customers&limit='+document.getElementById('limit').value+'&keyword='+document.getElementById('keyword').value,
then: data => {
// if(data.posts_report){
// processPostsReport(data.posts_report);
// }
return data.results.map(
form => [form.ID, form.name, form.email, form.phone, form.total_order]
);
},
total: data => data.total
},
columns: [
{
name: formipay_customers_page.columns.id,
width: '75px'
},
{
name: formipay_customers_page.columns.name,
formatter: (_, row) => gridjs.html(`
<b>${_}</b>
`)
},
{
name: formipay_customers_page.columns.email,
},
{
name: formipay_customers_page.columns.phone,
},
{
name: formipay_customers_page.columns.total_order,
formatter: (total_order, row) => gridjs.html(`<span class="status-label ${total_order}">${total_order}</span>`)
}
],
pagination: {
limit: document.getElementById('limit').value,
server: {
url: (prev, page, limit) => `${prev}&limit=${limit}&offset=${page * limit}`
},
summary: false
},
className: {
table: 'formipay-grid-table'
}
}).render(document.getElementById('formipay-customers'));
$('#limit, #keyword').on('change', function(){
formipay_table_grid.updateConfig({
server: {
url: formipay_customers_page.ajax_url+'?action=formipay-tabledata-customers&limit='+document.getElementById('limit').value+'&keyword='+document.getElementById('keyword').value,
then: data => data.results.map(
form => [form.ID, form.name, form.email, form.phone, form.total_order]
),
total: data => data.total
},
pagination: {
limit: document.getElementById('limit').value,
server: {
url: (prev, page, limit) => `${prev}&limit=${limit}&offset=${page * limit}`
},
summary: false
},
}).forceRender();
});
$(document).on('mouseover', 'td[data-column-id=form]', function(){
$(this).find('.post-action').css('visibility', 'visible');
});
$(document).on('mouseleave', 'td[data-column-id=form]', function(){
$(this).find('.post-action').css('visibility', 'hidden');
});
});

View File

@@ -0,0 +1,946 @@
jQuery(function($){
let wpcftoLoaded = false;
var checkWpcftoLoaded = setInterval(() => {
const container = $('.wpcfto-tab');
if(container.length > 0){
wpcftoLoaded = true;
$(document).trigger('wpcftoLoaded');
clearInterval(checkWpcftoLoaded);
}
}, 250);
$(document).on('wpcftoLoaded', function(){
update_option_to_data_mapping('initial');
});
function all_active_payments() {
var items = $('.payment_gateways #active .list-group-item');
var active_payments = [];
if(items.length > 0){
$.each(items, function(i, item){
var gateway = $(item).attr('id');
if(gateway.indexOf(':::') !== -1){
gateway = gateway.split(':::')[0];
gateway = gateway.replace('_', '-');
}
// $('[data-submenu=payments_'+gateway+']').show();
active_payments.push(gateway);
});
}
return active_payments;
}
function hide_inactive_payment_submenu() {
var div = $('[data-section=payments]').siblings('.wpcfto-submenus').find('[data-submenu]:not([data-submenu=payments_general])');
var active_payments = all_active_payments();
if(div.length > 0) {
$.each(div, function(x, y){
var gateway = $(y).attr('data-submenu').replace('payments_', '');
if(jQuery.inArray(gateway, active_payments) !== -1){
$(y).slideDown();
}else{
$(y).slideUp();
}
});
}
}
setTimeout(() => {
hide_inactive_payment_submenu();
}, 1000);
$(document).on('mouseleave', '.payment_gateways .list-group', function(){
hide_inactive_payment_submenu();
});
$(document).on('click', '.formipay-editor-nav .nav-link', function(){
$('.formipay-editor-nav').find('.nav-link').removeClass('active');
$(this).addClass('active');
$('.formipay-editor-tab-content.nav-content-section').addClass('d-none');
var tab_content = $(this).data('tab-content');
$('.formipay-editor-tab-content'+tab_content).removeClass('d-none');
});
$('.formipay-editor-nav .nav-item:first-child > .nav-link').trigger('click');
$(document).on('click', '#is_required', function(){
if($(this).is(':checked')) {
$(this).val('yes');
}else{
$(this).val('no');
}
});
$(document).on('blur change', '#add_field_form .field select.form-select', function(){
var array = ['divider', 'page_break'];
if( $.inArray( $(this).val(), array ) !== -1 ) {
$('#add_field_form .field:not(.main-field)').slideUp();
}else{
$('#add_field_form .field:not(.main-field):not(.has-conditional)').slideDown();
}
});
function formipay_sortable(){
$('#preview-wrapper').sortable({
opacity: 0.75,
items: '> .preview-field',
handle: 'span.grab',
change: function(event, ui) {
ui.placeholder.css({
visibility: 'visible',
border : '2px dashed #8c8f94',
borderRadius: '10px'
});
},
stop: function(event, ui){
update_option_to_data_mapping('update');
}
});
$('.repeater-child-wrapper').sortable({
opacity: 0.75,
items: '> .repeater-child-input',
handle: 'span.grab',
change: function(event, ui) {
ui.placeholder.css({
visibility: 'visible',
border : '2px dashed #cccccc',
borderRadius: '5px'
});
}
});
}
formipay_sortable();
$(document).on('change blur', '#add_field_form [name=label]', function(){
$('#add_field_form [name=field_id]').val($(this).val().toLowerCase().replace(' ', '_'));
});
$(document).on('click', '.add-option', function(e){
e.preventDefault();
var content = $(this).closest('.repeater-child-input').html();
$(this).closest('.repeater-child-wrapper').append(`
<div class="repeater-child-input d-flex justify-content-start align-items-start gap-2 my-2">`+content+`
</div>`);
$('.repeater-child-input:last-child').find('input').val('');
$('.repeater-child-input:last-child').find('.add-thumbnail').removeClass('text-info').addClass('text-white');
});
$(document).on('click', '.delete-option', function(e){
e.preventDefault();
$(this).closest('.repeater-child-input').remove();
});
$(document).on('click', 'input.option-field-toggle', function(){
var target = $(this).attr('data-child-field');
if($(this).is(':checked')){
$('.child-field-'+target).show();
}else{
$('.child-field-'+target).hide();
}
});
$(document).on('change', '#add_field_form .formipay-builder-field:not(.formipay-builder-option-field, [type=checkbox], [type=checkbox])', function(){
var value = $(this).val();
var name = $(this).attr('name');
var the_dependent = $('#add_field_form [data-if-'+name+']');
if('' !== value && the_dependent.length > 0){
// var all_dependents = $('.has-conditional');
$.each(the_dependent, function(x, y){
var decoded_value = JSON.parse($(y).attr('data-if-'+name));
if($.inArray(value, decoded_value) !== -1){
$(y).slideDown();
}else{
$(y).slideUp();
}
});
}
});
$(document).on('click', '.add-field', function(e){
e.preventDefault();
var option_image_toggle = 'no';
if($('#repeater-child-0_thumbnail').is(':checked')){
option_image_toggle = 'yes';
}
var option_value_toggle = 'no';
if($('#repeater-child-2_value').is(':checked')){
option_value_toggle = 'yes';
}
var option_amount_toggle = 'no';
if($('#repeater-child-3_amount').is(':checked')){
option_amount_toggle = 'yes';
}
var setup = {
'label' : $('#add_field_form [name=label]').val(),
'field_id' : $('#add_field_form [name=field_id]').val(),
'field_type' : $('#add_field_form [name=field_type]').val(),
'options_type' : $('#add_field_form [name=options_type]').val(),
'placeholder' : $('#add_field_form [name=placeholder]').val(),
'default_value' : $('#add_field_form [name=default_value]').val(),
'description' : $('#add_field_form [name=description]').val(),
'is_required' : $('#add_field_form [name=is_required]').val(),
'show_toggle' : {
'image' : option_image_toggle,
'value' : option_value_toggle,
'amount': option_amount_toggle
},
'layout' : $('#option_grid_columns').val()
};
var options = [];
var calculable_field = ['select', 'radio', 'checkbox'];
if($.inArray(setup.field_type, calculable_field) !== -1){
var single_option = $('.repeater-child-input');
if(single_option.length > 0){
$.each(single_option, function(a, b){
var check_qty;
if($(b).find('.repeater-child-input-qty').is(':checked')){
check_qty = 'yes';
}else{
check_qty = 'no';
}
var option = {
'image_id': $(b).find('.field-image-id').val(),
'image_url': $(b).find('.field-image-url').val(),
'label': $(b).find('.repeater-child-input-label').find('input').val(),
'value': $(b).find('.repeater-child-input-value').find('input').val(),
'amount': $(b).find('.repeater-child-input-amount').find('input').val(),
'weight': $(b).find('.repeater-child-input-weight').find('input').val(),
'qty': check_qty
}
options.push(option);
});
}
}
setup.field_options = options;
// console.log(setup);
var setup_string = JSON.stringify(setup);
var not_input = ['select', 'checkbox', 'radio'];
var is_required = '';
var asterisk = '';
if(setup.is_required == 'yes'){
is_required = '';
asterisk = ' <span style="color:red;">(*)</span>';
}
var hidden = '';
if(setup.field_type == 'hidden'){
hidden = ' style="opacity: .75;"'
}
if(!setup.calc_value){
setup.calc_value = 0;
}
var preview_content = '';
if($.inArray(setup.field_type, not_input) == -1){
if($.inArray(setup.field_type, ['divider', 'page_break']) !== -1){
preview_content = `
<div class="formipay-field w-100"`+hidden+`>
<div class="d-flex justify-content-between field-controls">
<label for="`+setup.field_id+`" class="label-`+setup.field_type+`">`+setup.label+`</label>
<div class="field-icons d-flex gap-2 align-items-center the_buttons">
<button class="btn btn-sm edit-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M5 19h1.425L16.2 9.225L14.775 7.8L5 17.575zm-2 2v-4.25L16.2 3.575q.3-.275.663-.425t.762-.15t.775.15t.65.45L20.425 5q.3.275.438.65T21 6.4q0 .4-.137.763t-.438.662L7.25 21zM19 6.4L17.6 5zm-3.525 2.125l-.7-.725L16.2 9.225z" />
</svg>
</button>
<button class="btn btn-sm delete-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M7 21q-.825 0-1.412-.587T5 19V6H4V4h5V3h6v1h5v2h-1v13q0 .825-.587 1.413T17 21zm2-4h2V8H9zm4 0h2V8h-2z" />
</svg>
</button>
</div>
</div>
<input type="hidden" name="`+setup.field_id+`_config" class="formipay-field-setup" value='`+setup_string+`'>
<span class="divider-line"></span>
<p class="formipay-inline-desc">`+setup.description+`</p>
</div>`;
}else if(setup.field_type == 'country_list') {
var country_json = formipay_admin.preset.country_list;
// Check if country_json is a string (indicating it might need to be parsed)
if (typeof country_json === 'string') {
try {
country_json = JSON.parse(country_json); // Parse the JSON string into an object
} catch (e) {
console.error('Error parsing JSON:', e); // Log any parsing errors
country_json = []; // Fallback to an empty array
}
}
// Validate the data type
if (!Array.isArray(country_json)) {
console.error('Expected an array but got:', country_json);
country_json = []; // Fallback to an empty array if not an array
}
var options_html = `<option>-- ${setup.placeholder}</option>`;
// Loop through each country object
$.each(country_json, function(index, country) {
// Assuming each country object has 'id' for the value and 'name' for the display text
options_html += `<option value="${country.name}">${country.name}</option>`;
});
preview_content = `
<div class="formipay-field w-100"`+hidden+`>
<div class="d-flex justify-content-between field-controls">
<label for="`+setup.field_id+`">`+setup.label+asterisk+`</label>
<div class="field-icons d-flex gap-2 align-items-center the_buttons">
<button class="btn btn-sm edit-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M5 19h1.425L16.2 9.225L14.775 7.8L5 17.575zm-2 2v-4.25L16.2 3.575q.3-.275.663-.425t.762-.15t.775.15t.65.45L20.425 5q.3.275.438.65T21 6.4q0 .4-.137.763t-.438.662L7.25 21zM19 6.4L17.6 5zm-3.525 2.125l-.7-.725L16.2 9.225z" />
</svg>
</button>
<button class="btn btn-sm delete-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M7 21q-.825 0-1.412-.587T5 19V6H4V4h5V3h6v1h5v2h-1v13q0 .825-.587 1.413T17 21zm2-4h2V8H9zm4 0h2V8h-2z" />
</svg>
</button>
</div>
</div>
<input type="hidden" name="`+setup.field_id+`_config" class="formipay-field-setup" value='`+setup_string+`'>
<select id="`+setup.field_id+`" class="formipay-input formipay-form-field" `+is_required+`>
`+options_html+`
</select>
<p class="formipay-inline-desc">`+setup.description+`</p>
</div>`;
}else if(setup.field_type !== 'textarea'){
preview_content = `
<div class="formipay-field w-100"`+hidden+`>
<div class="d-flex justify-content-between field-controls">
<label for="`+setup.field_id+`">`+setup.label+asterisk+`</label>
<div class="field-icons d-flex gap-2 align-items-center the_buttons">
<button class="btn btn-sm edit-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M5 19h1.425L16.2 9.225L14.775 7.8L5 17.575zm-2 2v-4.25L16.2 3.575q.3-.275.663-.425t.762-.15t.775.15t.65.45L20.425 5q.3.275.438.65T21 6.4q0 .4-.137.763t-.438.662L7.25 21zM19 6.4L17.6 5zm-3.525 2.125l-.7-.725L16.2 9.225z" />
</svg>
</button>
<button class="btn btn-sm delete-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M7 21q-.825 0-1.412-.587T5 19V6H4V4h5V3h6v1h5v2h-1v13q0 .825-.587 1.413T17 21zm2-4h2V8H9zm4 0h2V8h-2z" />
</svg>
</button>
</div>
</div>
<input type="hidden" name="`+setup.field_id+`_config" class="formipay-field-setup" value='`+setup_string+`'>
<input type="`+setup.field_type+`" id="`+setup.field_id+`" class="formipay-input formipay-form-field" placeholder="`+setup.placeholder+`" data-calc-value="`+setup.calc_value+`" `+is_required+` />
<p class="formipay-inline-desc">`+setup.description+`</p>
</div>`;
}else{
preview_content = `
<div class="formipay-field w-100"`+hidden+`>
<div class="d-flex justify-content-between field-controls">
<label for="`+setup.field_id+`">`+setup.label+asterisk+`</label>
<div class="field-icons d-flex gap-2 align-items-center the_buttons">
<button class="btn btn-sm edit-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M5 19h1.425L16.2 9.225L14.775 7.8L5 17.575zm-2 2v-4.25L16.2 3.575q.3-.275.663-.425t.762-.15t.775.15t.65.45L20.425 5q.3.275.438.65T21 6.4q0 .4-.137.763t-.438.662L7.25 21zM19 6.4L17.6 5zm-3.525 2.125l-.7-.725L16.2 9.225z" />
</svg>
</button>
<button class="btn btn-sm delete-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M7 21q-.825 0-1.412-.587T5 19V6H4V4h5V3h6v1h5v2h-1v13q0 .825-.587 1.413T17 21zm2-4h2V8H9zm4 0h2V8h-2z" />
</svg>
</button>
</div>
</div>
<input type="hidden" name="`+setup.field_id+`_config" class="formipay-field-setup" value='`+setup_string+`'>
<textarea rows="4" id="`+setup.field_id+`" class="formipay-input formipay-form-field" placeholder="`+setup.placeholder+`" data-calc-value="`+setup.calc_value+`" `+is_required+`></textarea>
<p class="formipay-inline-desc">`+setup.description+`</p>
</div>`;
}
}else{
if(setup.field_type == 'select'){
var options = setup.field_options;
var options_html = '';
if(setup.placeholder !== ''){
options_html = '<option>'+setup.placeholder+'</option>';
}
$.each(options, function(j, k){
var label = k.label;
var value = label;
if('' !== k.value && setup.show_toggle.value == 'yes'){
value = k.value;
}
var calc = 0;
if('' !== k.amount && setup.show_toggle.amount == 'yes'){
calc = k.amount;
}
options_html += '<option value="'+value+'" data-calc-value="'+calc+'">'+label+'</option>';
});
preview_content = `
<div class="formipay-field w-100"`+hidden+`>
<div class="d-flex justify-content-between field-controls">
<label for="`+setup.field_id+`">`+setup.label+asterisk+`</label>
<div class="field-icons d-flex gap-2 align-items-center the_buttons">
<button class="btn btn-sm edit-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M5 19h1.425L16.2 9.225L14.775 7.8L5 17.575zm-2 2v-4.25L16.2 3.575q.3-.275.663-.425t.762-.15t.775.15t.65.45L20.425 5q.3.275.438.65T21 6.4q0 .4-.137.763t-.438.662L7.25 21zM19 6.4L17.6 5zm-3.525 2.125l-.7-.725L16.2 9.225z" />
</svg>
</button>
<button class="btn btn-sm delete-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M7 21q-.825 0-1.412-.587T5 19V6H4V4h5V3h6v1h5v2h-1v13q0 .825-.587 1.413T17 21zm2-4h2V8H9zm4 0h2V8h-2z" />
</svg>
</button>
</div>
</div>
<input type="hidden" name="`+setup.field_id+`_config" class="formipay-field-setup" value='`+setup_string+`'>
<select id="`+setup.field_id+`" class="formipay-input formipay-form-field" `+is_required+`>
`+options_html+`
</select>
<p class="formipay-inline-desc">`+setup.description+`</p>
</div>`;
}else{
var options = setup.field_options;
var options_html = '';
$.each(options, function(j, k){
var name = setup.field_id+`-`+j;
if(setup.field_type == 'radio'){
name = setup.field_id;
}
var label = k.label;
var value = label;
if('' !== k.value && setup.show_toggle.value == 'yes'){
value = k.value;
}
var calc = 0;
if('' !== k.amount && setup.show_toggle.amount == 'yes'){
calc = k.amount;
}
var image = '';
if('' !== k.image_id && '' !== k.image_url){
image = `<img src="`+k.image_url+`" style="width: 100%; height: 150px; object-fit: contain;">`;
}
options_html +=
`<div class="formipay-checkbox-group">
`+image+`
<input type="`+setup.field_type+`" id="`+setup.field_id+`-`+j+`" name="`+name+`" class="formipay-input formipay-form-field" value="`+k.value+`" />
<label for="`+setup.field_id+`-`+j+`">`+k.label+`</label>
</div>`;
});
if(setup.layout == ''){
setup.layout = 1;
}
preview_content = `
<div class="formipay-field w-100"`+hidden+`>
<div class="d-flex justify-content-between field-controls">
<label for="`+setup.field_id+`">`+setup.label+asterisk+`</label>
<div class="field-icons d-flex gap-2 align-items-center the_buttons">
<button class="btn btn-sm edit-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M5 19h1.425L16.2 9.225L14.775 7.8L5 17.575zm-2 2v-4.25L16.2 3.575q.3-.275.663-.425t.762-.15t.775.15t.65.45L20.425 5q.3.275.438.65T21 6.4q0 .4-.137.763t-.438.662L7.25 21zM19 6.4L17.6 5zm-3.525 2.125l-.7-.725L16.2 9.225z" />
</svg>
</button>
<button class="btn btn-sm delete-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M7 21q-.825 0-1.412-.587T5 19V6H4V4h5V3h6v1h5v2h-1v13q0 .825-.587 1.413T17 21zm2-4h2V8H9zm4 0h2V8h-2z" />
</svg>
</button>
</div>
</div>
<input type="hidden" name="`+setup.field_id+`_config" class="formipay-field-setup" value='`+setup_string+`'>
<div class="formipay-checkbox-wrapper" style="display: grid; grid-template-columns: repeat(`+setup.layout+`, 1fr); gap: 10px;">
`+options_html+`
</div>
<p class="formipay-inline-desc">`+setup.description+`</p>
</div>`;
}
}
var hidden = is_required = '';
if(setup.type == 'hidden'){
hidden = ' style="display: none;"';
}
if(setup.require == 'yes'){
is_required = ' required';
}
// Check if any
var edit_to = $('.add-field').attr('data-edit-to');
var the_existed_field = $('.preview-field[data-field="'+edit_to+'"]');
if(the_existed_field.length > 0){
$('.preview-field[data-field="'+edit_to+'"]').html(`
<span class="grab pb-4">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#000" d="M9 20q-.825 0-1.412-.587T7 18t.588-1.412T9 16t1.413.588T11 18t-.587 1.413T9 20m6 0q-.825 0-1.412-.587T13 18t.588-1.412T15 16t1.413.588T17 18t-.587 1.413T15 20m-6-6q-.825 0-1.412-.587T7 12t.588-1.412T9 10t1.413.588T11 12t-.587 1.413T9 14m6 0q-.825 0-1.412-.587T13 12t.588-1.412T15 10t1.413.588T17 12t-.587 1.413T15 14M9 8q-.825 0-1.412-.587T7 6t.588-1.412T9 4t1.413.588T11 6t-.587 1.413T9 8m6 0q-.825 0-1.412-.587T13 6t.588-1.412T15 4t1.413.588T17 6t-.587 1.413T15 8" />
</svg>
</span>
`+preview_content+`
`);
}else{
$('#preview-wrapper').append(`
<div class="preview-field d-flex gap-2 align-items-center" data-field="`+setup.field_id+`" data-field-type="`+setup.field_type+`">
<span class="grab pb-4">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#000" d="M9 20q-.825 0-1.412-.587T7 18t.588-1.412T9 16t1.413.588T11 18t-.587 1.413T9 20m6 0q-.825 0-1.412-.587T13 18t.588-1.412T15 16t1.413.588T17 18t-.587 1.413T15 20m-6-6q-.825 0-1.412-.587T7 12t.588-1.412T9 10t1.413.588T11 12t-.587 1.413T9 14m6 0q-.825 0-1.412-.587T13 12t.588-1.412T15 10t1.413.588T17 12t-.587 1.413T15 14M9 8q-.825 0-1.412-.587T7 6t.588-1.412T9 4t1.413.588T11 6t-.587 1.413T9 8m6 0q-.825 0-1.412-.587T13 6t.588-1.412T15 4t1.413.588T17 6t-.587 1.413T15 8" />
</svg>
</span>
`+preview_content+`
</div>
`);
}
$('.preview-field[data-field="'+setup.field_id+'"]').attr('data-field-type', setup.field_type);
// scissors icon
if(setup.field_type == 'page_break'){
$('.preview-field[data-field="'+setup.field_id+'"]').append(`
<span class="scissors">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#000" d="m12 14l-2.35 2.35q.2.375.275.8T10 18q0 1.65-1.175 2.825T6 22t-2.825-1.175T2 18t1.175-2.825T6 14q.425 0 .85.075t.8.275L10 12L7.65 9.65q-.375.2-.8.275T6 10q-1.65 0-2.825-1.175T2 6t1.175-2.825T6 2t2.825 1.175T10 6q0 .425-.075.85t-.275.8L20.6 18.6q.675.675.3 1.538T19.575 21q-.275 0-.537-.112t-.463-.313zm3-3l-2-2l5.575-5.575q.2-.2.463-.312T19.574 3q.95 0 1.313.875t-.313 1.55zM6 8q.825 0 1.413-.587T8 6t-.587-1.412T6 4t-1.412.588T4 6t.588 1.413T6 8m6 4.5q.2 0 .35-.15t.15-.35t-.15-.35t-.35-.15t-.35.15t-.15.35t.15.35t.35.15M6 20q.825 0 1.413-.587T8 18t-.587-1.412T6 16t-1.412.588T4 18t.588 1.413T6 20" />
</svg>
</span>
`)
}else{
$('.preview-field[data-field="'+setup.field_id+'"] > span.scissors').remove();
}
var builder_fields = $('#add_field_form').find('.formipay-builder-field');
if(builder_fields.length > 0){
$.each(builder_fields, function(a, b){
if($(b).attr('type') == 'checkbox'){
$(b).val('no').prop('checked', false);
}else{
$(b).val('');
}
});
}
$('.repeater-child-input:not(:first-child)').remove();
$('.repeater-child-input > input').val('');
$('.repeater-child-input > .add-thumbnail').removeClass('text-info').addClass('text-white');
$('.repeater-child-input .check-qty').prop('checked', false);
$('#add_field_form .field.has-conditional').slideUp();
var all_option_toggle = $('.option-field-toggle');
$.each(all_option_toggle, function(p, q){
if($(q).is(':checked')){
$(q).trigger('click');
}
});
$('.child-field-image-wrapper').find('img').attr('src', '').hide();
$('.child-field-image-wrapper').find('i').attr('src', '').show();
$('#add_field_form .field:not(.has-conditional)').show();
$('[name=field_type]').val('text').change();
$('.add-field').removeAttr('data-edit-to').text('Add Field');
formipay_sortable();
setTimeout(() => {
update_option_to_data_mapping('update');
}, 1000);
});
$(document).on('change', '#customer_data-buyer_allow_choose_country_code', function() {
update_option_to_data_mapping('update');
});
function update_option_to_data_mapping(initiation) {
var fields = $('#preview-wrapper').find('input[type=hidden]');
var options = [];
$.each(fields, function(increment, field){
var value = $(field).val();
var config = JSON.parse(value);
options.push(config);
});
var target = $('#customer_data').find('select');
target.html('');
target.append(`<option value="">${formipay_admin.config.datamapping.placeholder}</option>`);
if(options.length > 0){
$.each(options, function(increment, option){
target.append(`<option value="${option.field_id}">${option.label}</option>`);
});
}
if(initiation == 'initial'){
$.ajax({
type: 'post',
url: formipay_admin.ajax_url,
data: {
action: 'formipay_check_for_data_mapping_saved_value',
post: $('#post_ID').val(),
_wpnonce: formipay_admin.nonce
},
success: function(res) {
$.each(res, function(name, value){
if(value){
$(`[name="${name}"]`).attr('data-current-value', value).val(value);
}
});
}
});
}else if(initiation == 'update'){
$.each(target, function(increment, select){
const current_value = $(select).attr('data-current-value');
$(select).attr('data-current-value', current_value).val(current_value);
})
}
}
$(document).on('change', '#customer_data select', function() {
var value = $(this).val();
$(this).attr('data-current-value', value);
});
$(document).on('click', '.delete-preview-field', function(e){
e.preventDefault();
$(this).parents('.preview-field').remove();
update_option_to_data_mapping('update');
});
$(document).on('click', '.edit-preview-field', function(e){
e.preventDefault();
// recondition all fields
$('.option-field-toggle').prop('checked', false);
$('.repeater-child-input:not(:first-child)').remove();
$('.repeater-child-input:first-child').find('input').val('');
// $('.repeater-child-input:first-child').find('.add-thumbnail').removeClass('text-info').addClass('text-white');
var setup = $(this).closest('.preview-field').find('.formipay-field-setup').val();
setup = JSON.parse(setup);
console.log(setup);
$.each(setup, function(x, y){
if(x == 'field_options'){
if(y.length > 0){
var first_repeater = $('.repeater-child-input:first-child')
var repeater_template = first_repeater.html();
var repeater_wrapper = $('.repeater-child-wrapper');
$.each(y, function(p, q){
repeater_wrapper.append(
`<div class="repeater-child-input d-flex justify-content-start align-items-start gap-2 my-2">
`+repeater_template+`
</div>`);
var repeater_target = $('.repeater-child-input:last-child');
repeater_target.find('.the_title').text(q.label);
repeater_target.find('.child-field-label').find('input').val(q.label);
repeater_target.find('.child-field-value').find('input').val(q.value);
repeater_target.find('.child-field-amount').find('input').val(q.amount);
if(q.qty == 'yes'){
repeater_target.find('.check-qty').val('yes').prop('checked', true);
}else{
repeater_target.find('.check-qty').val('no').prop('checked', false);
}
if('' !== q.image){
repeater_target.find('.field-image-id').val(q.image_id);
repeater_target.find('.field-image-url').val(q.image_url);
repeater_target.find('img').attr('src', q.image_url).removeClass('d-none');
repeater_target.find('.child-field-image').hide();
// repeater_target.find('.add-thumbnail').removeClass('text-white').addClass('text-info');
}
repeater_target.show();
first_repeater.hide();
first_repeater.remove();
});
$('.repeater-child-input:first-child').find('.open-option');
}
}else if(x == 'layout'){
$('#add_field_form [name="option_grid_columns"]').val(y);
}else{
$('#add_field_form [name="' + x + '"]').val(y);
}
});
$('#add_field_form [name=is_required]').prop('checked', setup.is_required === 'yes');
// Handle show_toggle options
if ('show_toggle' in setup) {
if(setup.show_toggle.image === 'yes'){
$('#repeater-child-0_thumbnail').trigger('click');
}
if(setup.show_toggle.value === 'yes'){
$('#repeater-child-2_value').trigger('click');
}
if(setup.show_toggle.amount === 'yes'){
$('#repeater-child-3_amount').trigger('click');
}
}
formipay_sortable();
// Trigger recondition and form change
$('.formipay-builder-field[name=field_type]').trigger('change');
$('.add-field').attr('data-edit-to', setup.field_id).text('Edit Field');
});
if( $('[name=daterange]').val() == '' ){
$('[name=daterange]').daterangepicker({
timePicker: true,
startDate: moment().startOf('hour'),
endDate: moment().startOf('hour').add(32, 'hour'),
showDropdowns: true,
timePicker24Hour: true,
locale: {
format: 'D-M-Y HH:mm'
}
});
}else{
$('[name=daterange]').daterangepicker({
timePicker: true,
showDropdowns: true,
timePicker24Hour: true,
locale: {
format: 'D-M-Y HH:mm'
}
});
}
$(document).on('click', '[role=switch]', function(){
var id = $(this).attr('id');
if($(this).is(':checked')){
$('#add_field_form [data-if-'+id+'=active]').show();
$(this).val('no');
}else{
$('#add_field_form [data-if-'+id+'=active]').hide();
$(this).val('yes');
}
});
$(document).on('click change', '#add_field_form [type=radio]', function(){
var id = $(this).attr('name');
var value = $(this).val();
$('#add_field_form [data-if-'+id+']').hide();
if($(this).is(':checked')){
$('#add_field_form [data-if-'+id+'='+value+']').show();
}
});
$('[type=radio]').trigger('change');
$(document).on('change', '.config-dropdown', function(){
var id = $(this).attr('id');
var value = $(this).val();
var attr_value = $('#add_field_form [data-if-'+id+']');
$('#add_field_form [data-if-'+id+']').hide();
if(attr_value.length > 0){
$.each(attr_value, function(x,y){
var this_attr_value = $(y).attr('data-if-'+id);
if(this_attr_value.indexOf('::') !== -1){
var split = this_attr_value.split('::');
if($.inArray(value, split) !== -1){
$(y).show();
}
}else{
if(this_attr_value == value){
$(y).show();
}
}
});
}
});
$('.config-dropdown').trigger('change');
$(document).on('click', '.open-option', function(e){
e.preventDefault();
$(this).find('.bi').toggleClass('bi-arrow-up').toggleClass('bi-arrow-down');
$(this).closest('.child-fields-wrapper').find('.child-field-wrapper').slideToggle();
$(this).closest('.child-field-title').toggleClass('option-detail-opened');
});
var all_checkbox = $('[type="checkbox"]');
if(all_checkbox.length > 0){
$.each(all_checkbox, function(a,b){
if($(b).val() == 'yes'){
$(b).val('no').trigger('click');
}
});
}
function modify_payment_box_behavior() {
var allbox = $('#payments multi_checkbox');
var checkbox_input = $('.payments-payment input[type=checkbox]');
var checked_value = [];
if(checkbox_input.length > 0){
$.each(checkbox_input, function(x, y){
if($(y).is(':checked')){
checked_value.push($(y).val());
$('[data-field=wpcfto_addon_option_payment_'+$(y).val()+']').show();
}else{
$('[data-field=wpcfto_addon_option_payment_'+$(y).val()+']').hide();
}
});
}
}
setTimeout(() => {
modify_payment_box_behavior();
}, 500);
$(document).on('click', '.payments-payment input[type=checkbox]', function(){
modify_payment_box_behavior();
});
$(document).on('mouseover', 'span.grab', function(){
$(this).css('pointer', 'grab');
});
$(document).on('click', 'span.grab', function(){
$(this).css('pointer', 'grabbing');
});
$(document).on('change blur', '.child-field-label input.formipay-builder-field', function(){
$(this).closest('.child-fields-wrapper').find('.the_title').text($(this).val());
});
});
jQuery(function($){
// setTimeout(() => {
// var autocomplete_fields = $('.wpcfto-box .autocomplete');
// if(autocomplete_fields.length > 0){
// $.each(autocomplete_fields, function(increment, field){
// var label = $(field).find('.wpcfto-field-aside__label').text();
// var placeholder = formipay_admin.config.autocomplete.placeholder.replace('{field_label}', label);
// var search_input = $(field).find('input');
// search_input.attr('placeholder', placeholder);
// search_input.parent().attr('data-input-placeholder', placeholder);
// });
// }
// }, 1000);
// $(document).on('mouseleave blur focusout', '.wpcfto-autocomplete-search input', function(){
// var placeholder = $(this).parent().attr('data-input-placeholder');
// setTimeout(() => {
// $(this).attr('placeholder', placeholder);
// }, 500);
// });
$( document ).on( 'click', '.add-thumbnail', function( event ) {
var gallery_items_frame;
const $el = $( this );
var target_field = $el.attr('data-field');
var target_id = $el.siblings('.'+target_field+'-id');
var target_url = $el.siblings('.'+target_field+'-url');
var selected = target_id.val();
var able_multiple = $el.attr('data-able-multiple');
event.preventDefault();
if ( gallery_items_frame ) {
// Select the attachment when the frame opens
gallery_items_frame.on( 'open', function() {
var selection = gallery_items_frame.state().get( 'selection' );
selection.reset( selected ? [ wp.media.attachment( selected ) ] : [] );
});
// Open the modal.
gallery_items_frame.open();
return;
}
// Create the media frame.
gallery_items_frame = wp.media.frames.gallery_items = wp.media({
// Set the title of the modal.
title: 'Choose or upload media',
button: {
text: 'Select'
},
states: [
new wp.media.controller.Library({
title: 'Choose or upload media',
filterable: 'all',
multiple: able_multiple
})
]
});
// Select the attachment when the frame opens
gallery_items_frame.on( 'open', function() {
var selection = gallery_items_frame.state().get( 'selection' );
selection.reset( selected ? [ wp.media.attachment( selected ) ] : [] );
});
gallery_items_frame.on( 'select', function() {
attachment = gallery_items_frame.state().get('selection').first().toJSON();
target_id.val( attachment.id );
target_url.val( attachment.url );
if(target_id.val() !== ''){
// $el.removeClass('text-white').addClass('text-info d-none');
if($el.hasClass('btn')){
$el.siblings('i').hide();
}else{
$el.hide();
}
$el.siblings('img').removeClass('d-none').attr('src', attachment.url).show();
}else{
// $el.removeClass('text-info d-none').addClass('text-white');
if($el.hasClass('btn')){
$el.siblings('i').show();
}else{
$el.show();
}
$el.siblings('img').addClass('d-none').hide();
}
});
// Open the modal.
gallery_items_frame.open();
});
$( document ).on( 'click', '.trumbowyg-button-group:has(.trumbowyg-insertImage-button)', function( event ) {
var gallery_items_frame;
event.preventDefault();
// Create the media frame.
gallery_items_frame = wp.media.frames.gallery_items = wp.media({
// Set the title of the modal.
title: 'Choose or upload media',
button: {
text: 'Select'
},
states: [
new wp.media.controller.Library({
title: 'Choose or upload media',
filterable: 'all',
multiple: false
})
]
});
gallery_items_frame.on( 'select', function() {
attachment = gallery_items_frame.state().get('selection').first().toJSON();
var target_input_url = $('.trumbowyg-modal.trumbowyg-fixed-top .trumbowyg-input-html input');
var target_confirm = $('.trumbowyg-modal.trumbowyg-fixed-top .trumbowyg-modal-submit');
target_input_url.val( attachment.url );
target_confirm.trigger('click');
});
// Open the modal.
gallery_items_frame.open();
});
});

View File

@@ -0,0 +1,174 @@
jQuery(document).ready(function($) {
function getParam(key) {
var paramsStr = window.location.search.substr(1, window.location.search.length),
paramsArr = paramsStr.split("&"),
items = [];
for (var i = 0; i < paramsArr.length; i++) {
items[paramsArr[i].split("=")[0]] = paramsArr[i].split("=")[1];
}
if (key != "" && key != undefined) {
// return single
if (items[key] != undefined) {
return items[key];
} else {
return null;
}
} else {
// return all (array)
return items;
}
};
if (getParam('post')){
// Fetch data via AJAX
$.ajax({
url: formipay_admin.ajax_url, // WordPress AJAX URL
method: 'GET',
data: {
action: 'fetch_formipay_settings',
post_id: formipay_admin.form_id, // Assuming you have post ID available globally,
_wpnonce: formipay_admin.nonce
},
success: function(response) {
var source = $("#preview-template").html();
var template = Handlebars.compile(source);
var context = {
fields: response.data.fields
};
var html = template(context);
$("#preview-wrapper").html(html);
}
});
}
// Fetch data via AJAX
$.ajax({
url: formipay_admin.ajax_url, // WordPress AJAX URL
method: 'GET',
data: {
action: 'fetch_formipay_fields',
},
success: function(response) {
var source = $("#add-field-form-template").html();
var template = Handlebars.compile(source);
var context = {
fields: response.data.fields
};
var html = template(context);
$("#add_field_form").html(html);
$('#add_field_form .field select.form-select').trigger('change');
}
});
// Handlebars helper for comparing equality
Handlebars.registerHelper('ifEquals', function(arg1, arg2, options) {
return (arg1 == arg2) ? options.fn(this) : options.inverse(this);
});
// Handlebars helper for checking inequality
Handlebars.registerHelper('ifNotEquals', function(arg1, arg2, options) {
return (arg1 != arg2) ? options.fn(this) : options.inverse(this);
});
// Handlebars helper for checking if a value is in a list
Handlebars.registerHelper('ifIn', function(value, list, options) {
return (list.split(' ').indexOf(value) > -1) ? options.fn(this) : options.inverse(this);
});
// Handlebars helper for checking if a value is in a list
Handlebars.registerHelper('ifNotIn', function(value, list, options) {
return (list.split(' ').indexOf(value) > -1) ? options.inverse(this) : options.fn(this);
});
// Handlebars helper for JSON stringify
Handlebars.registerHelper('json', function(context) {
return JSON.stringify(context);
});
// Handlebars helper to concatenate custom classes
Handlebars.registerHelper('custom_class', function(custom_class) {
return (custom_class && Array.isArray(custom_class)) ? ' '+custom_class.join(' ') : '';
});
// Handlebars helper to handle conditional classes and display properties
Handlebars.registerHelper('conditional_class', function(conditional) {
return (conditional && conditional.length > 0) ? ' has-conditional' : '';
});
// Handlebars helper to return label class
Handlebars.registerHelper('labelClass', function(fieldType) {
return 'label-' + fieldType;
});
// Handlebars helper to return name attribute for checkbox and radio inputs
Handlebars.registerHelper('name', function(fieldType, fieldId, index) {
return (fieldType == 'radio') ? fieldId : fieldId + '-' + index;
});
Handlebars.registerHelper('display', function(conditional) {
var display = '';
if (conditional) {
display = ' style="display:none"';
if (Array.isArray(conditional)) {
conditional.forEach(function(cond) {
display += ' data-if-' + cond.key + "='" + JSON.stringify(cond.value) + "'";
});
}
}
return display;
});
// Handlebars helper to format option text
Handlebars.registerHelper('formatOption', function(option) {
return option.charAt(0).toUpperCase() + option.slice(1).replace('_', ' ');
});
// Handlebars helper for toggle display property
Handlebars.registerHelper('toggleDisplay', function(toggle) {
return (toggle == 'yes') ? ' style="display:none;"' : '';
});
// Handlebars helper for set grid column for checkbox and radio
Handlebars.registerHelper('layoutColumn', function(layout) {
return (layout !== '') ? layout : 1;
});
// Handlebars helper for set the first option as selected
Handlebars.registerHelper('selectedTheFirstOption', function(index) {
return (index == 0) ? ' selected' : '';
});
// Handlebars helper for set the first option as selected
Handlebars.registerHelper('countryListOptions', function() {
var country_json = formipay_admin.preset.country_list;
// Check if country_json is a string (indicating it might need to be parsed)
if (typeof country_json === 'string') {
try {
country_json = JSON.parse(country_json); // Parse the JSON string into an object
} catch (e) {
console.error('Error parsing JSON:', e); // Log any parsing errors
country_json = []; // Fallback to an empty array
}
}
// Validate the data type
if (!Array.isArray(country_json)) {
console.error('Expected an array but got:', country_json);
country_json = []; // Fallback to an empty array if not an array
}
var options_html = ``; // Initialize options_html variable
// Loop through each country object
$.each(country_json, function(index, country) {
// Assuming each country object has 'id' for the value and 'name' for the display text
options_html += `<option value="${country.name}">${country.name}</option>`;
});
return options_html;
});
});

View File

@@ -0,0 +1,430 @@
jQuery(function($){
Handlebars.registerHelper('ifEquals', function(arg1, arg2, options) {
return (arg1 == arg2) ? options.fn(this) : options.inverse(this);
});
Handlebars.registerHelper('nameToTitle', function(arg) {
var parse = arg.split('_');
var output = [];
$.each(parse, function( a, b ){
if(b.length <= 3){
output.push(b.toUpperCase());
}else{
output.push(b);
}
});
return output.join(' ');
});
Handlebars.registerHelper('parsePaymentInfo', function(arg) {
var explode = arg.split('-');
var explode2 = explode[0].split(':::');
var gateway = explode2[0].split('_').join(' ');
var channel = explode2[1];
return gateway + ' - ' + channel;
});
Handlebars.registerHelper('ifKeyExists', function(key, obj, options) {
// Check if the key exists in the object
if (obj && obj.hasOwnProperty(key)) {
// If it exists, execute the block
return options.fn(this);
}
// If it does not exist, execute the inverse block (if provided)
return options.inverse(this);
});
function ucWords(input) {
return input
.replace(/_/g, ' ') // Replace underscores with spaces
.toLowerCase() // Convert entire string to lowercase first
.replace(/^(.)/, function(char) { return char.toUpperCase(); }) // Capitalize the first letter of the first word
.replace(/ (.)/g, function(char) { return char.toUpperCase(); }); // Capitalize the first letter after each space
}
let order_id = $('#order_id').val();
function load_order_data() {
$.ajax({
type: 'post',
url: formipay_order_details_page.ajax_url,
data: {
action: 'formipay_load_order_data',
order: order_id,
_wpnonce: formipay_order_details_page.nonce
},
success: function (res) {
console.log(res);
var source = $("#order-item-row-template").html();
var template = Handlebars.compile(source);
var context = {
items: res.items
};
var html = template(context);
$("#order-items-table tbody").html(html);
$('#order-total').html(res.total_formatted);
$('#order_status').val(res.status);
var source = $("#form-data-item-template").html();
var template = Handlebars.compile(source);
var context = {
datas: res.form_data
};
var html = template(context);
$("#form-data-list").html(html);
var editFormDataButton = $('.edit-transaction-data').attr('data-loaded-button-text');
$('.edit-transaction-data').text(editFormDataButton).prop('disabled', false);
var source = $("#form-data-item-template").html();
var template = Handlebars.compile(source);
var meta_data = [];
$.each(res.meta_data, function(index, meta){
if(meta.name !== 'access_method' && meta.name !== 'access_password'){
meta_data.push(meta);
}
});
var context = {
datas: meta_data
};
var html = template(context);
$("#submission-detail-list").html(html);
var source = $("#notification-data-template").html();
var template = Handlebars.compile(source);
var context = {
datas: res.notification.sort().reverse()
};
var html = template(context);
$("#notification-list").html(html);
var source = $("#transaction-timeline-item").html();
var template = Handlebars.compile(source);
var context = {
datas: res.transaction_timeline.sort().reverse()
};
var html = template(context);
$("#transaction-list").html(html);
var passMethod = {
'magic_link': 'Magic Link',
'static_password': 'Static Password'
}
var source = $('#thankyou-access-template').html();
var template = Handlebars.compile(source);
var context = {
data: {
link: res.thankyou.link,
pass_method: res.thankyou.pass_method,
pass_method_label: passMethod[res.thankyou.pass_method],
pass_word: res.thankyou.pass_word
}
};
var html = template(context);
$('#access-detail-list').html(html);
$('#access_method').val(res.thankyou.pass_method).trigger('change');
var editFormDataButton = $('.edit-access-data').attr('data-loaded-button-text');
$('.edit-access-data').text(editFormDataButton).prop('disabled', false);
if(res.thankyou.pass_method == 'static_password'){
$('li.access-password p').text(res.thankyou.pass_word);
$('li.access-password').removeClass('d-none');
}
}
});
}
function set_loading_button(selector, loadingText = '') {
var buttonText = selector.text();
selector.attr('data-button-text', buttonText);
selector.prop('disabled', true);
if(loadingText !== '') {
selector.html(`
<span class="spinner-border spinner-border-sm" aria-hidden="true"></span>
<span role="status">${loadingText}</span>
`);
}else{
selector.html(`
<span class="spinner-border spinner-border-sm" aria-hidden="true"></span>
<span class="visually-hidden" role="status">${loadingText}</span>
`);
}
}
function remove_loading_button(selector) {
var buttonText = selector.attr('data-button-text');
selector.prop('disabled', false);
selector.html(buttonText);
}
load_order_data();
$(document).on('click', '.timeline-item-image', function(){
var imageSrc = $(this).attr('src');
$('#image-ligthbox img').attr('src', imageSrc);
$('#image-ligthbox').modal('show');
});
$('#order_status').on('change', function() {
var status = $(this).val();
var order_id = $(this).data('order-id');
Swal.fire({
html: formipay_order_details_page.order_detail.change_order_status_confirmation,
icon: 'question',
confirmButtonText: formipay_order_details_page.order_detail.change_order_status_button_confirm,
cancelButtonText: formipay_order_details_page.order_detail.change_order_status_button_cancel,
showCancelButton: true,
reverseButtons: true
}).then((result) => {
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_order_details_page.ajax_url,
data: {
action: 'formipay_change_order_status',
id: order_id,
status: status,
_wpnonce: formipay_order_details_page.nonce
},
success: function (res) {
if(res.success){
Swal.fire({
html: res.data.message,
icon: 'success'
});
}else{
Swal.fire({
html: res.data.message,
icon: 'error'
});
}
}
});
}
});
});
$('.edit-transaction-data').on('click', function(e) {
e.preventDefault();
var $this_button = $(this);
$.ajax({
type: 'post',
url: formipay_order_details_page.ajax_url,
data: {
action: 'formipay_check_editable_field',
order_id: formipay_order_details_page.order_id,
_wpnonce: formipay_order_details_page.nonce
},
beforeSend: function() {
set_loading_button($this_button, formipay_order_details_page.order_detail.edit_button_loading_text);
},
success: function(res) {
remove_loading_button($this_button);
$('.edit-transaction-data').addClass('d-none');
$('.update-transaction-buttons').removeClass('d-none');
$.each(res, function(config, field_data){
var field_id = field_data.field_id;
var field_current_value = $(`[data-field-name=${field_id}]`).text();
$(`[data-field-name=${field_id}]`).attr('data-current-value', field_current_value);
$(`[data-field-name=${field_id}]`).html(`
<input type="${field_data.field_type}" name="${field_id}" value="${$.trim(field_current_value)}" class="form-control rounded border border-secondary-subtle">
`);
});
}
})
});
$('.update-transaction-data').on('click', function(e){
e.preventDefault();
var $this_button = $(this);
var editable_inputs = $('#form-data-list').find('input');
var editable_field_values = [];
$.each(editable_inputs, function(i, input){
var this_input = {
name: $(input).attr('name'),
value: $(input).val()
}
editable_field_values.push(this_input);
});
$.ajax({
type: 'post',
url: formipay_order_details_page.ajax_url,
data: {
action: 'formipay_update_editable_field_data',
order_id: formipay_order_details_page.order_id,
new_values: editable_field_values,
_wpnonce: formipay_order_details_page.nonce
},
beforeSend: function() {
set_loading_button($this_button, formipay_order_details_page.order_detail.update_button_loading_text);
},
success: function(res){
remove_loading_button($this_button);
if(res.success){
$('.edit-transaction-data').removeClass('d-none');
$('.update-transaction-buttons').addClass('d-none');
$.each(editable_inputs, function(i, input){
var new_value = $(input).val();
$(input).parent().removeAttr('data-current-value');
$(input).parent().text(new_value);
});
Swal.fire({
html: res.data.message,
icon: 'success'
});
}else{
$.each(editable_inputs, function(i, input){
var current_value = $(input).parent().attr('data-current-value');
$(input).val(current_value);
});
Swal.fire({
html: res.data.message,
icon: 'error'
});
}
}
});
});
$('.cancel-transaction-data').on('click', function(e){
e.preventDefault();
var editable_inputs = $('#form-data-list').find('input');
$.each(editable_inputs, function(i, input){
var current_value = $(input).parent().attr('data-current-value');
$(input).parent().text(current_value);
});
$('.edit-transaction-data').removeClass('d-none');
$('.update-transaction-buttons').addClass('d-none');
});
$('.edit-access-data').on('click', function(e){
e.preventDefault();
var $this_button = $(this);
set_loading_button($this_button, formipay_order_details_page.order_detail.edit_button_loading_text);
var current_method = $('li.access-method').attr('data-access-method');
$('li.access-method').find('p').after(`
<select name="access_method" id="access_method" class="form-select w-100 rounded border border-secondary-subtle" data-order-id="${$('#order_id').val()}" style="max-width: unset;">
<option value="magic_link" ${(current_method == 'magic_link') ? 'selected' : ''}>${formipay_order_details_page.order_detail.pass_method.magic_link}</option>
<option value="static_password" ${(current_method == 'static_password') ? 'selected' : ''}>${formipay_order_details_page.order_detail.pass_method.static_password}</option>
</select>
`);
$('#access_method').trigger('change');
$('li.access-method').find('p').addClass('d-none');
remove_loading_button($this_button);
$('.edit-access-data').addClass('d-none');
$('.update-access-buttons').removeClass('d-none');
});
$(document).on('change', '#access_method', function(){
var access_password_li = $(this).closest('li').siblings('.access-password');
if($(this).val() == 'static_password'){
var password = access_password_li.attr('data-access-password');
access_password_li.removeClass('d-none');
access_password_li.find('p').after(`
<input type="text" id="access_password" class="form-control w-100 rounded border border-secondary-subtle" value="${ password}">
`);
access_password_li.find('p').addClass('d-none');
}else{
access_password_li.addClass('d-none');
access_password_li.find('input').remove();
}
});
function normalize_access_data_card() {
var accessMethod = $('li.access-method').attr('data-access-method');
var accessPassword = $('li.access-password').attr('data-access-password');
$('li.access-method select').remove();
$('li.access-method p').removeClass('d-none');
$('.edit-access-data').removeClass('d-none');
$('.update-access-buttons').addClass('d-none');
if( accessMethod == 'magic_link'){
$('li.access-password').addClass('d-none');
}
$('li.access-method p').text(ucWords(accessMethod)).removeClass('d-none');
$('li.access-password p').text(ucWords(accessPassword)).removeClass('d-none');
$('li.access-password input').remove();
}
$('.cancel-access-data').on('click', function(e){
e.preventDefault();
normalize_access_data_card();
});
$('.update-access-data').on('click', function(e){
e.preventDefault();
var $this_button = $(this);
var this_method = $('#access_method').val();
var this_password = $('#access_password').val()
$.ajax({
type: 'post',
url: formipay_order_details_page.ajax_url,
data: {
action: 'formipay_update_digital_access',
order_id: formipay_order_details_page.order_id,
method: this_method,
password: this_password,
_wpnonce: formipay_order_details_page.nonce
},
beforeSend: function() {
set_loading_button($this_button, formipay_order_details_page.order_detail.update_button_loading_text);
},
success: function(res){
remove_loading_button($this_button);
if(res.success){
$('li.access-method').attr('data-access-method', this_method)
if(this_method == 'static_password'){
$('li.access-password').attr('data-access-password', this_password)
}
Swal.fire({
html: res.data.message,
icon: 'success'
});
}else{
Swal.fire({
html: res.data.message,
icon: 'error'
});
}
normalize_access_data_card();
}
});
});
$(document).on('click', '.formipay-copy-button', function(e) {
e.preventDefault();
var $this = $(this);
var copiedtext = $(this).attr("data-copy-value");
if (navigator.clipboard) {
navigator.clipboard.writeText(copiedtext)
.then(() => {
$this.html('<i class="bi bi-check-circle-fill"></i> '+$this.attr('data-copied-text'));
setTimeout(() => {
$this.html('<i class="bi bi-copy"></i> '+$this.attr('data-copy-text'));
}, 1200);
})
.catch((error) => {
$this.html('<i class="bi bi-exclamation-circle-fill"></i> '+$this.attr('data-not-copied-text'));
setTimeout(() => {
$this.html('<i class="bi bi-copy"></i> '+$this.attr('data-copy-text'));
}, 1200);
});
} else {
$this.html('<i class="bi bi-check-circle-fill"></i> '+$this.attr('data-not-copied-text'));
setTimeout(() => {
$this.html('<i class="bi bi-copy"></i> '+$this.attr('data-copy-text'));
}, 1200);
}
});
});

View File

@@ -0,0 +1,256 @@
document.addEventListener('DOMContentLoaded', function () {
const formChoices = new Choices('#products', {
searchEnabled: true,
searchChoices: false, // Prevent Choices.js from filtering the local list
searchResultLimit: 10, // Optional: Limit visible results
placeholder: true,
placeholderValue: formipay_orders_page.filter_form.products.placeholder,
noResultsText: formipay_orders_page.filter_form.products.noresult_text,
itemSelectText: '',
});
const currencyChoices = new Choices('#currencies', {
searchEnabled: true,
searchChoices: false, // Prevent Choices.js from filtering the local list
searchResultLimit: 10, // Optional: Limit visible results
placeholder: true,
placeholderValue: formipay_orders_page.filter_form.currencies.placeholder,
noResultsText: formipay_orders_page.filter_form.currencies.noresult_text,
itemSelectText: '',
allowHTML: true
});
const searchInputs = document.querySelectorAll('.choices__input--cloned');
let typingTimer;
searchInputs.forEach((searchInput) => {
searchInput.addEventListener('input', function () {
const query = searchInput.value;
if (query.length >= 3) {
clearTimeout(typingTimer);
typingTimer = setTimeout(() => {
// Find the wrapper (e.g., .product or .currency)
const parentWrapper = searchInput.closest('.product, .currency');
let searchType = ''; // Initialize search type
// Determine the type based on the parent wrapper's class
if (parentWrapper) {
if (parentWrapper.classList.contains('product')) {
searchType = 'form';
} else if (parentWrapper.classList.contains('currency')) {
searchType = 'currency';
}
}
// Fetch choices with the determined type
fetchChoices(query, searchType);
}, 300); // Add a debounce delay
}
});
});
function fetchChoices(query, type) {
fetch(formipay_orders_page.ajax_url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
},
body: new URLSearchParams({
action: 'formipay_orders_get_choices',
search: query,
type: type, // Pass the type to the server,
_wpnonce: formipay_orders_page.nonce
}),
})
.then((response) => response.json())
.then((data) => {
const currentChoices = type === 'form' ? formChoices : currencyChoices;
currentChoices.clearChoices();
currentChoices.setChoices(data, 'value', 'label', true);
})
.catch((error) => console.error('Error:', error));
}
document.getElementById('reset-filter').addEventListener('click', function(){
formChoices.removeActiveItems();
currencyChoices.removeActiveItems();
const input = document.getElementById('order_id');
const event = new Event('change', { bubbles: true });
input.value = '';
input.dispatchEvent(event);
});
});
jQuery(function($){
let formipay_table_grid = new gridjs.Grid({
server: {
url: formipay_orders_page.ajax_url+'?action=formipay-tabledata-orders&order_status='+document.getElementById('post_status').value+'&product='+document.getElementById('products').value+'&currency='+document.getElementById('currencies').value+'&order_id='+document.getElementById('order_id').value+'&_wpnonce='+formipay_orders_page.nonce,
then: data => {
if(data.posts_report){
processPostsReport(data.posts_report);
}
return data.results.map(
order => [order.ID, order.ID, order.date, order.form, order.total, order.payment_gateway, order.status]
);
},
total: data => data.total
},
columns: [
{
id: 'checkbox',
name: gridjs.html(`<input type="checkbox" id="select-all-rows">`),
width: '50px',
formatter: (_, row) => gridjs.html(
`<input type="checkbox" class="formipay-row-checkbox" data-id="${row.cells[0].data}">`
)
},
{
name: formipay_orders_page.columns.id,
width: '75px'
},
{
name: formipay_orders_page.columns.date,
formatter: (_, row) => gridjs.html('<span>' + _.split(' ').join('</span><br><span style="font-size: smaller;">') + '</span>')
},
{
name: formipay_orders_page.columns.form,
formatter: (_, row) => gridjs.html(`
<b>${_}</b><br>
<span class="post-action" style="visibility: hidden;">
<a href="${formipay_orders_page.site_url}/wp-admin/admin.php?page=formipay-orders&order_id=${row.cells[0].data}">details</a> | <a href="#" class="delete-order" data-id="${row.cells[0].data}">delete</a>
</span>
`)
},
{
name: formipay_orders_page.columns.total,
formatter: (_, row) => gridjs.html(`
<span class="grand_total">
<span class="currency">
<img src="${_.flag}" height="18">
${_.name}
</span>
<span class="the-total">${_.value}</span>
</span>
`)
},
formipay_orders_page.columns.payment_gateway,
{
name: formipay_orders_page.columns.status,
formatter: (status, row) => gridjs.html(`<span class="status-label ${status}">${status}</span>`)
}
],
pagination: {
limit: document.getElementById('limit').value,
server: {
url: (prev, page, limit) => `${prev}&limit=${limit}&offset=${page * limit}`
},
summary: false
},
className: {
table: 'formipay-grid-table'
}
}).render(document.getElementById('formipay-orders'));
var $tableContainer = $('.formipay-grid-table');
var $deleteBtn = $('#formipay-delete-selected');
function updateDeleteButtonVisibility() {
if ($tableContainer.find('.formipay-row-checkbox:checked').length > 0) {
$deleteBtn.show();
} else {
$deleteBtn.hide();
}
}
// Handle row and "select all" checkbox changes
$tableContainer.on('change', '.formipay-row-checkbox', function() {
updateDeleteButtonVisibility();
});
// Handle row and "select all" checkbox changes
$tableContainer.on('change', '#select-all-rows', function() {
const is_checked = $(this).is(':checked');
$tableContainer.find('.formipay-row-checkbox').prop('checked', is_checked);
updateDeleteButtonVisibility();
});
// Handle delete button click
$deleteBtn.on('click', function() {
var selectedIds = $tableContainer.find('.formipay-row-checkbox:checked').map(function() {
return $(this).data('id');
}).get();
if (selectedIds.length > 0) {
Swal.fire({
icon: 'info',
html: formipay_orders_page.modal.bulk_delete.question,
showCancelButton: true,
confirmButtonText: formipay_orders_page.modal.bulk_delete.confirmButton,
cancelButtonText: formipay_orders_page.modal.bulk_delete.cancelButton
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_orders_page.ajax_url,
data: {
action: 'formipay-bulk-delete-access-item',
ids: selectedIds,
_wpnonce: formipay_orders_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_table_grid.forceRender();
$tableContainer.find('.formipay-row-checkbox').prop('checked', false);
updateDeleteButtonVisibility();
refresh_table_with_filter();
}
});
}
});
}
});
function refresh_table_with_filter() {
formipay_table_grid.updateConfig({
server: {
url: formipay_orders_page.ajax_url+'?action=formipay-tabledata-orders&order_status='+document.getElementById('post_status').value+'&product='+document.getElementById('products').value+'&currency='+document.getElementById('currencies').value+'&order_id='+document.getElementById('order_id').value+'&_wpnonce='+formipay_orders_page.nonce,
then: data => data.results.map(
order => [order.ID, order.ID, order.date, order.form, order.total, order.payment_gateway, order.status]
),
total: data => data.total
},
pagination: {
limit: document.getElementById('limit').value,
server: {
url: (prev, page, limit) => `${prev}&limit=${limit}&offset=${page * limit}`
},
summary: false
},
}).forceRender();
}
$('.form-tool, #post_status, #products, #currencies, #order_id').on('change', function(){
refresh_table_with_filter();
});
$(document).on('mouseover', 'td[data-column-id=form]', function(){
$(this).find('.post-action').css('visibility', 'visible');
});
$(document).on('mouseleave', 'td[data-column-id=form]', function(){
$(this).find('.post-action').css('visibility', 'hidden');
});
});

View File

@@ -0,0 +1,69 @@
function numberFormat(nStr) {
nStr = parseFloat(nStr).toFixed(2);
var x = nStr.split('.');
var x1 = x[0];
var x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
function processPostsReport(data) {
Object.keys(data).forEach(function(status) {
// Update the text of elements matching the class
var elements = document.querySelectorAll('.' + status + '-post-count');
elements.forEach(function(element) {
element.textContent = ' (' + data[status] + ')';
});
// Handle the 'trash' status specifically
if (status === 'trash' && data[status] > 0) {
var wrapper = document.querySelector('.post-status-wrapper');
if (wrapper) {
wrapper.innerHTML += ' | <a data-value="trash">Trash</a><span class="draft-post-count"> (' + data[status] + ')</span>';
}
}
});
}
jQuery(function($){
$('.post-status-wrapper a').on('click', function(e){
e.preventDefault();
$('.post-status-wrapper a').removeAttr('data-active');
$(this).attr('data-active', 'true');
$('#post_status').val($(this).data('value')).trigger('change');
});
});
(function() {
var supportsPassive = false;
try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
supportsPassive = true;
}
});
window.addEventListener("testPassive", null, opts);
window.removeEventListener("testPassive", null, opts);
} catch (e) {}
if (!supportsPassive) return;
var origAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, options) {
// Only patch touchstart and touchmove if options is not explicitly passive
if (
(type === 'touchstart' || type === 'touchmove') &&
(options === undefined || options === false || (typeof options === 'object' && !options.passive))
) {
options = options || {};
if (typeof options === 'object') {
options.passive = true;
}
}
return origAddEventListener.call(this, type, listener, options);
};
})();

View File

@@ -0,0 +1,359 @@
jQuery(function ($) {
$('a[href="admin.php?page=formipay-products"]').addClass('current').closest('li').addClass('current');
function autoset_variation_name() {
var repeater_single = $('.product_variation_attributes.repeater [parent_repeater="parent"] > .wpcfto-field-content > .wpcfto-repeater-single');
$.each(repeater_single, function (key, parent) {
var repeater_child = $(parent).find('[field_native_name="product_variation_attributes"]');
var attribute_name = repeater_child.find(`[name="product_variation_attributes_${key}_attribute_name"]`).val();
var attribute_type = repeater_child.find(`[name="product_variation_attributes_${key}_attribute_type"]`).val();
var repeater_child_single = repeater_child.find('.wpcfto-repeater-single');
$.each(repeater_child_single, function (index, child) {
var label_field = $(`input[name="product_variation_attributes_${key}_attribute_variations_${index}_variation_label"]`);
var name_field = $(`input[name="product_variation_attributes_${key}_attribute_variations_${index}_variation_name"]`);
var color_field = $(`input[name="product_variation_attributes_${key}_attribute_variations_${index}_variation_color"]`);
var color_field_row = color_field.closest('.wpcfto-repeater-field');
if (attribute_type == 'color') {
color_field_row.show();
} else {
color_field_row.hide();
}
});
});
}
$(document).on('change blur', '[field_native_name_inner="variation_label"] input', function () {
autoset_variation_name();
});
$(document).on('click', '.stm_metaboxes_grid .stm_metaboxes_grid__inner .wpcfto-repeater .addArea', function () {
autoset_variation_name();
});
var onMetaboxLoaded = setInterval(() => {
var repeater_single = $('.product_variation_attributes.repeater [parent_repeater="parent"] > .wpcfto-field-content > .wpcfto-repeater-single');
if (repeater_single.length > 0) {
autoset_variation_name();
clearInterval(onMetaboxLoaded);
}
}, 250);
var waitForTable = setInterval(() => {
if ($('#product-variables-table').length > 0) {
clearInterval(waitForTable);
// --- PERBAIKAN UTAMA DI SINI ---
Vue.component('price-input', {
// Gunakan 'value' sebagai prop, sesuai konvensi v-model Vue 2
props: {
value: [Number, String], // Diubah dari modelValue
currencySymbol: String,
currencyDecimalDigits: {
type: Number,
default: 2
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
inputValue: this.value // Diubah dari modelValue
};
},
watch: {
// Amati perubahan pada prop 'value'
value(newValue) { // Diubah dari modelValue
this.inputValue = newValue;
}
},
methods: {
onInput(e) {
const value = e.target.value;
this.inputValue = value;
// Pancarkan event 'input', sesuai konvensi v-model Vue 2
this.$emit('input', value); // Diubah dari 'update:modelValue'
}
},
computed: {
stepValue() {
return Math.pow(10, -this.currencyDecimalDigits);
}
},
template: `
<div class="price-input-wrapper">
<span class="price-currency">{{ currencySymbol }}</span>
<input type="number" :value="inputValue" @input="onInput" :step="stepValue" placeholder="0" :disabled="disabled" />
</div>
`
});
// --- AKHIR DARI PERBAIKAN ---
new Vue({
el: '#product-variables-table',
data() {
return {
tableRows: [],
deletedKeys: [],
isPhysical: window.product_details?.product_is_physical || false,
pricingMethod: window.product_details?.product_pricing_method || 'auto',
manualPrices: [],
productHasVariation: window.product_details?.product_has_variation || false,
jsonValue: '[]',
attributeRepeaterWatcher: null,
manualPricesWatcher: null,
_debounceTimer: null,
productType: window.product_details?.product_type || 'digital',
currencyDecimalDigits: parseInt(window.product_details?.default_currency_decimal_digits) || 2,
currencySymbol: window.product_details?.default_currency_symbol || '$'
};
},
async mounted() {
await this.initializeOrClearTable();
this.setupAttributeRepeaterSync();
this.setupManualPricesSync();
const typeRadios = document.querySelectorAll('input[name="product_type"]');
typeRadios.forEach(radio => {
radio.addEventListener('change', e => {
this.productType = e.target.value;
this.isPhysical = e.target.value === 'physical';
});
});
const pricingRadios = document.querySelectorAll('input[name="product_pricing_method"]');
pricingRadios.forEach(radio => {
radio.addEventListener('change', async e => {
this.pricingMethod = e.target.value;
await this.rebuildTable();
});
});
const hasVariationToggle = document.querySelector('input[name="product_has_variation"]');
if (hasVariationToggle) {
hasVariationToggle.addEventListener('change', async (e) => {
this.productHasVariation = e.target.checked;
await this.initializeOrClearTable();
});
}
},
beforeDestroy() {
if (this.attributeRepeaterWatcher) {
this.attributeRepeaterWatcher.disconnect();
}
if (this.manualPricesWatcher) {
this.manualPricesWatcher.disconnect();
}
},
methods: {
async initializeOrClearTable() {
if (!this.productHasVariation) {
this.tableRows = [];
this.updateJson();
return;
}
await this.syncManualPrices();
await this.loadProductVariables();
},
_ensureRowDataStructure(row) {
if (this.pricingMethod === 'manual') {
if (typeof row.prices === 'undefined') {
row.prices = JSON.parse(JSON.stringify(this.manualPrices));
delete row.price;
delete row.sale;
}
} else {
if (typeof row.price === 'undefined') {
row.price = 0;
row.sale = 0;
delete row.prices;
}
}
if (typeof row.expanded === 'undefined') {
row.expanded = false;
}
return row;
},
async loadProductVariables() {
if (!this.productHasVariation) {
this.tableRows = [];
this.updateJson();
return;
}
const postId = window.formipayProductId || $('input[name="post_ID"]').val();
if (!postId) {
await this.buildFromAttributes();
return;
}
try {
const res = await $.ajax({
url: ajaxurl,
method: 'POST',
data: {
action: 'get_product_variables',
post_id: postId
}
});
if (res.success && Array.isArray(res.data) && res.data.length) {
this.tableRows = res.data.map(row => this._ensureRowDataStructure(row));
this.deletedKeys = [];
this.updateJson();
} else {
await this.buildFromAttributes();
}
} catch {
await this.buildFromAttributes();
}
},
async buildFromAttributes() {
if (!this.productHasVariation) {
this.tableRows = [];
this.updateJson();
return;
}
try {
const attributes = await this.getAttributeRepeaterData();
if (!attributes.length) {
this.tableRows = [];
this.updateJson();
return;
}
const combinations = this.getAllCombinations(attributes);
const filtered = combinations.filter(c => !this.deletedKeys.includes(c.key));
const newRows = filtered.map(c => {
const existing = this.tableRows.find(r => r.key === c.key);
if (existing) {
this._ensureRowDataStructure(existing);
return Object.assign(existing, {
name: c.label
});
}
let newRowData = {
key: c.key,
name: c.label,
stock: '',
weight: 0,
active: true,
};
return this._ensureRowDataStructure(newRowData);
});
this.tableRows = newRows;
this.updateJson();
} catch (e) {
console.error("Error building from attributes:", e);
this.tableRows = [];
this.updateJson();
}
},
getAttributeRepeaterData() {
return new Promise((resolve, reject) => {
let attempts = 0;
const maxAttempts = 100;
const interval = setInterval(() => {
const el = $('#variation-product_variation_attributes');
if (el.length && el.val()) {
try {
const data = JSON.parse(el.val());
clearInterval(interval);
resolve(Array.isArray(data) ? data : []);
} catch {
clearInterval(interval);
reject(new Error('Invalid JSON in attribute repeater'));
}
} else if (++attempts >= maxAttempts) {
clearInterval(interval);
reject(new Error('Attribute repeater data not found'));
}
}, 50);
});
},
getAllCombinations(attributes) {
const attrVars = attributes
.map(attr => (attr.attribute_variations || []).map(v => ({
label: v.variation_label
})))
.filter(arr => arr.length > 0);
if (!attrVars.length) return [];
const combine = (arrs) => arrs.reduce((a, b) => a.flatMap(d => b.map(e => [].concat(d, e))));
const combos = combine(attrVars);
return combos.map(combo => {
const labels = Array.isArray(combo) ? combo.map(c => c.label) : [combo.label];
return {
key: labels.join('||'),
label: labels.join(' - ')
};
});
},
setupAttributeRepeaterSync() {
const target = document.getElementById('variation-product_variation_attributes');
if (!target) return;
const observer = new MutationObserver(() => {
clearTimeout(this._debounceTimer);
this._debounceTimer = setTimeout(() => this.buildFromAttributes(), 300);
});
observer.observe(target, {
attributes: true,
attributeFilter: ['value']
});
this.attributeRepeaterWatcher = observer;
},
async syncManualPrices() {
const el = document.getElementById('general-product_prices');
if (el && el.value) {
try {
const pricesData = JSON.parse(el.value);
this.manualPrices = Array.isArray(pricesData) ? pricesData : [];
} catch (e) {
this.manualPrices = [];
}
} else {
this.manualPrices = [];
}
},
setupManualPricesSync() {
const target = document.getElementById('general-product_prices');
if (!target) return;
const observer = new MutationObserver(async () => {
await this.syncManualPrices();
if (this.pricingMethod === 'manual') {
this.tableRows.forEach(row => {
const newPricesFromRepeater = this.manualPrices;
let reconciledPrices = row.prices.filter(existingPrice =>
newPricesFromRepeater.some(newPrice => newPrice.currency === existingPrice.currency)
);
newPricesFromRepeater.forEach(newPrice => {
const isAlreadyThere = reconciledPrices.some(p => p.currency === newPrice.currency);
if (!isAlreadyThere) {
reconciledPrices.push(JSON.parse(JSON.stringify(newPrice)));
}
});
row.prices = reconciledPrices;
});
}
this.updateJson();
});
observer.observe(target, {
attributes: true,
attributeFilter: ['value']
});
this.manualPricesWatcher = observer;
},
updateJson() {
this.jsonValue = JSON.stringify(this.tableRows);
},
async rebuildTable() {
await this.initializeOrClearTable();
}
},
watch: {
tableRows: {
handler() {
this.updateJson();
},
deep: true
}
}
});
}
}, 250);
});

View File

@@ -0,0 +1,217 @@
jQuery(function($){
$('a[href="admin.php?page=formipay-products"]').addClass('current').closest('li').addClass('current');
function autoset_variation_name() {
var repeater_single = $('.product_variation_attributes.repeater [parent_repeater="parent"] > .wpcfto-field-content > .wpcfto-repeater-single');
$.each(repeater_single, function(key, parent){
var repeater_child = $(parent).find('[field_native_name="product_variation_attributes"]');
var attribute_name = repeater_child.find(`[name="product_variation_attributes_${key}_attribute_name"]`).val();
var attribute_type = repeater_child.find(`[name="product_variation_attributes_${key}_attribute_type"]`).val();
var repeater_child_single = repeater_child.find('.wpcfto-repeater-single');
$.each(repeater_child_single, function(index, child){
var label_field = $(`input[name="product_variation_attributes_${key}_attribute_variations_${index}_variation_label"]`);
var name_field = $(`input[name="product_variation_attributes_${key}_attribute_variations_${index}_variation_name"]`);
var color_field = $(`input[name="product_variation_attributes_${key}_attribute_variations_${index}_variation_color"]`);
var color_field_row = color_field.closest('.wpcfto-repeater-field');
if(attribute_type == 'color'){
color_field_row.show();
}else{
color_field_row.hide();
}
});
});
}
$(document).on('change blur', '[field_native_name_inner="variation_label"] input', function(){
autoset_variation_name();
});
$(document).on('click', '.stm_metaboxes_grid .stm_metaboxes_grid__inner .wpcfto-repeater .addArea', function() {
autoset_variation_name();
});
var onMetaboxLoaded = setInterval(() => {
var repeater_single = $('.product_variation_attributes.repeater [parent_repeater="parent"] > .wpcfto-field-content > .wpcfto-repeater-single');
if(repeater_single.length > 0){
autoset_variation_name();
clearInterval(onMetaboxLoaded);
}
}, 250);
var waitForTable = setInterval(() => {
if ($('#product-variables-table').length > 0) {
clearInterval(waitForTable);
new Vue({
el: '#product-variables-table',
data() {
return {
tableRows: [],
deletedKeys: [],
isPhysical: window.product_details?.product_is_physical || false,
jsonValue: '[]',
attributeRepeaterWatcher: null,
_debounceTimer: null,
productType: window.product_details?.product_type || 'digital', // default, will update on mount
productCurrencyRaw: window.product_details?.product_currency || 'USD:::United States dollar:::$',
currencyDecimalDigits: parseInt(window.product_details?.product_currency_decimal_digits) || 2,
currencyDecimalSymbol: window.product_details?.product_currency_decimal_symbol || '.',
currencyThousandSeparator: window.product_details?.product_currency_thousand_separator || ',',
};
},
async mounted() {
await this.loadProductVariables();
this.setupAttributeRepeaterSync();
// Listen for changes on product_type radios to update reactive data
const radios = document.querySelectorAll('input[name="product_type"]');
radios.forEach(radio => {
radio.addEventListener('change', e => {
this.productType = e.target.value;
this.isPhysical = e.target.value == 'physical';
this.rebuildTable(); // Rebuild the table on type change
});
});
// Listen for changes on product_currency select
const currencySelect = document.querySelector('select[name="product_currency"]');
if (currencySelect) {
currencySelect.addEventListener('change', (e) => {
this.productCurrencyRaw = e.target.value;
});
}
// Initialize currency values
this.productCurrencyRaw = window.product_details?.product_currency || 'USD:::United States dollar:::$';
},
beforeDestroy() {
if (this.attributeRepeaterWatcher) {
this.attributeRepeaterWatcher.disconnect();
}
},
methods: {
async loadProductVariables() {
const postId = window.formipayProductId || $('input[name="post_ID"]').val();
if (!postId) {
await this.buildFromAttributes();
return;
}
try {
const res = await $.ajax({
url: ajaxurl,
method: 'POST',
data: { action: 'get_product_variables', post_id: postId }
});
if (res.success && Array.isArray(res.data) && res.data.length) {
this.tableRows = res.data;
this.deletedKeys = [];
this.updateJson();
} else {
await this.buildFromAttributes();
}
} catch {
await this.buildFromAttributes();
}
},
async buildFromAttributes() {
try {
const attributes = await this.getAttributeRepeaterData();
if (!attributes.length) {
this.tableRows = [];
this.updateJson();
return;
}
const combinations = this.getAllCombinations(attributes);
const filtered = combinations.filter(c => !this.deletedKeys.includes(c.key));
const newRows = filtered.map(c => {
const existing = this.tableRows.find(r => r.key === c.key);
return existing ? Object.assign(existing, { name: c.label }) : {
key: c.key,
name: c.label,
stock: '',
price: 0,
sale: 0,
weight: 0,
active: true,
};
});
this.tableRows = newRows;
this.updateJson();
} catch (e) {
this.tableRows = [];
this.updateJson();
}
},
getAttributeRepeaterData() {
return new Promise((resolve, reject) => {
let attempts = 0;
const maxAttempts = 100;
const interval = setInterval(() => {
const el = $('#variation-product_variation_attributes');
if (el.length && el.val()) {
try {
const data = JSON.parse(el.val());
clearInterval(interval);
resolve(data);
} catch {
clearInterval(interval);
reject(new Error('Invalid JSON in attribute repeater'));
}
} else if (++attempts >= maxAttempts) {
clearInterval(interval);
reject(new Error('Attribute repeater data not found'));
}
}, 50);
});
},
getAllCombinations(attributes) {
if (!attributes.length) return [];
const attrVars = attributes.map(attr =>
(attr.attribute_variations || []).map(v => ({ label: v.variation_label }))
).filter(arr => arr.length > 0);
if (!attrVars.length) return [];
const combine = (arrs) => arrs.reduce((a, b) => a.flatMap(d => b.map(e => [].concat(d, e))));
const combos = combine(attrVars);
return combos.map(combo => {
const labels = Array.isArray(combo) ? combo.map(c => c.label) : [combo.label];
return { key: labels.join('||'), label: labels.join(' - ') };
});
},
setupAttributeRepeaterSync() {
const target = document.getElementById('variation-product_variation_attributes');
if (!target) return;
const observer = new MutationObserver(mutations => {
for (const m of mutations) {
if (m.type === 'attributes' && m.attributeName === 'value') {
clearTimeout(this._debounceTimer);
this._debounceTimer = setTimeout(() => this.buildFromAttributes(), 200);
}
}
});
observer.observe(target, { attributes: true, attributeFilter: ['value'] });
this.attributeRepeaterWatcher = observer;
},
updateJson() {
this.jsonValue = JSON.stringify(this.tableRows);
},
rebuildTable() {
this.loadProductVariables();
}
},
watch: {
tableRows: {
handler() { this.updateJson(); },
deep: true
}
}
});
}
}, 250);
});

View File

@@ -0,0 +1,68 @@
jQuery(function($){
$(document).on('click', '.show-instruction', function(){
$('.global-paypal-instruction').slideToggle();
$(this).text(function(i, text){
return text === 'Show Instruction' ? 'Hide Instruction' : 'Show Instruction';
});
});
$(document).on('click', '.formipay-connect-paypal', function(e) {
e.preventDefault();
$.ajax({
url: formipay_admin_setting.ajax_url,
type: 'POST',
data: {
action: 'formipay_oneclick_connect',
nonce: formipay_admin_setting.nonce
},
beforeSend: function() {
$('#connect-status').html('<div class="notice notice-info"><p>Initiating PayPal connection...</p></div>');
},
success: function(response) {
if (response.success) {
// Open PayPal auth in popup
const popup = window.open(
response.data.auth_url,
'paypal_oauth',
'width=600,height=700,scrollbars=yes'
);
// Listen for message from popup
window.addEventListener('message', function(event) {
if (event.data.type === 'formipay-paypal-connect') {
if (event.data.success) {
$('#connect-status').html(`
<div class="notice notice-success">
<p>${event.data.message}</p>
<p>Webhook ID: ${event.data.webhook_id}</p>
</div>
`);
} else {
$('#connect-status').html(`
<div class="notice notice-error">
<p>${event.data.message}</p>
</div>
`);
}
}
});
} else {
$('#connect-status').html(`
<div class="notice notice-error">
<p>Connection failed: ${response.data}</p>
</div>
`);
}
},
error: function() {
$('#connect-status').html(`
<div class="notice notice-error">
<p>Connection failed: Server error</p>
</div>
`);
}
});
});
});

View File

@@ -0,0 +1,30 @@
jQuery(document).ready(function($) {
// Smooth toggle for postboxes
$('.postbox').each(function() {
$(this).on('click', '.hndle', function() {
$(this).next('.inside').slideToggle();
});
});
// Add class for better styling
$('#title').attr('placeholder', 'Enter title here...');
$('#publishing-action .spinner').html(`
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<rect width="6" height="14" x="1" y="4" fill="#0073aa">
<animate id="svgSpinnersBarsScaleFade0" fill="freeze" attributeName="y" begin="0;svgSpinnersBarsScaleFade1.end-0.25s" dur="0.75s" values="1;5" />
<animate fill="freeze" attributeName="height" begin="0;svgSpinnersBarsScaleFade1.end-0.25s" dur="0.75s" values="22;14" />
<animate fill="freeze" attributeName="opacity" begin="0;svgSpinnersBarsScaleFade1.end-0.25s" dur="0.75s" values="1;0.2" />
</rect>
<rect width="6" height="14" x="9" y="4" fill="#0073aa" opacity="0.4">
<animate fill="freeze" attributeName="y" begin="svgSpinnersBarsScaleFade0.begin+0.15s" dur="0.75s" values="1;5" />
<animate fill="freeze" attributeName="height" begin="svgSpinnersBarsScaleFade0.begin+0.15s" dur="0.75s" values="22;14" />
<animate fill="freeze" attributeName="opacity" begin="svgSpinnersBarsScaleFade0.begin+0.15s" dur="0.75s" values="1;0.2" />
</rect>
<rect width="6" height="14" x="17" y="4" fill="#0073aa" opacity="0.3">
<animate id="svgSpinnersBarsScaleFade1" fill="freeze" attributeName="y" begin="svgSpinnersBarsScaleFade0.begin+0.3s" dur="0.75s" values="1;5" />
<animate fill="freeze" attributeName="height" begin="svgSpinnersBarsScaleFade0.begin+0.3s" dur="0.75s" values="22;14" />
<animate fill="freeze" attributeName="opacity" begin="svgSpinnersBarsScaleFade0.begin+0.3s" dur="0.75s" values="1;0.2" />
</rect>
</svg>
`);
});

View File

@@ -0,0 +1,69 @@
jQuery(function($){
$( document ).on( 'click', '.open-media-modal', function( event ) {
var gallery_items_frame;
const $el = $( this );
var target_field = $el.attr('data-target-field');
var target_id = $el.siblings('.'+target_field+'-id');
var target_url = $el.siblings('.'+target_field+'-url');
var image_preview = $el.siblings('.image-preview');
var selected = target_id.val();
var able_multiple = $el.attr('data-able-multiple');
event.preventDefault();
if ( gallery_items_frame ) {
// Select the attachment when the frame opens
gallery_items_frame.on( 'open', function() {
var selection = gallery_items_frame.state().get( 'selection' );
selection.reset( selected ? [ wp.media.attachment( selected ) ] : [] );
});
// Open the modal.
gallery_items_frame.open();
return;
}
// Create the media frame.
gallery_items_frame = wp.media.frames.gallery_items = wp.media({
// Set the title of the modal.
title: 'Choose or upload media',
button: {
text: 'Select'
},
states: [
new wp.media.controller.Library({
title: 'Choose or upload media',
filterable: 'all',
multiple: able_multiple
})
]
});
// Select the attachment when the frame opens
gallery_items_frame.on( 'open', function() {
var selection = gallery_items_frame.state().get( 'selection' );
selection.reset( selected ? [ wp.media.attachment( selected ) ] : [] );
});
gallery_items_frame.on( 'select', function() {
// We set multiple to false so only get one image from the uploader
attachment = gallery_items_frame.state().get('selection').first().toJSON();
// Do something with attachment.id and/or attachment.url here
target_url.val( attachment.url );
target_id.val( attachment.id );
// $el.find('.bi-image-alt').hide();
image_preview.html('<img src="'+attachment.url+'" width="150px">');
// $el.attr('data-id', attachment.id);
});
// Open the modal.
gallery_items_frame.open();
});
});

View File

@@ -0,0 +1,354 @@
document.addEventListener('DOMContentLoaded', function () {
const formChoices = new Choices('#products', {
searchEnabled: true,
searchChoices: false, // Prevent Choices.js from filtering the local list
searchResultLimit: 10, // Optional: Limit visible results
placeholder: true,
placeholderValue: formipay_access_page.filter_form.products.placeholder,
noResultsText: formipay_access_page.filter_form.products.noresult_text,
itemSelectText: '',
});
const searchInput = document.querySelector('.choices__input--cloned');
let typingTimer;
searchInput.addEventListener('input', function () {
const query = searchInput.value;
if (query.length >= 3) {
clearTimeout(typingTimer);
typingTimer = setTimeout(() => {
fetchChoices(query);
}, 300); // Add a debounce delay
}
});
function fetchChoices(query) {
fetch(formipay_access_page.ajax_url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
},
body: new URLSearchParams({
action: 'formipay_access_items_get_products',
search: query,
nonce: formipay_access_page.nonce
}),
})
.then((response) => response.json())
.then((data) => {
formChoices.clearChoices();
formChoices.setChoices( data, 'value', 'label', true);
})
.catch((error) => console.error('Error:', error));
}
document.getElementById('reset-filter').addEventListener('click', function(){
formChoices.removeActiveItems();
const event = new Event('change', { bubbles: true });
document.getElementById('orderby').value = 'ID';
document.getElementById('sort_by').value = 'desc';
document.getElementById('keyword').value = '';
document.getElementById('keyword').dispatchEvent(event);
});
});
jQuery(function($){
let formipay_table_grid = new gridjs.Grid({
server: {
url: formipay_access_page.ajax_url+'?action=formipay-tabledata-access-items&post_status='+document.getElementById('post_status').value+'&product='+document.getElementById('products').value+'&orderby='+document.getElementById('orderby').value+'&sort='+document.getElementById('sort_by').value+'&search='+document.getElementById('keyword').value+'&_wpnonce='+formipay_access_page.nonce,
then: data => {
if(data.posts_report){
processPostsReport(data.posts_report);
}
return data.results.map(
access => [access.ID, access.ID, access.title, access.type, access.products, access.status]
);
},
total: data => data.total
},
columns: [
{
id: 'checkbox',
name: gridjs.html(`<input type="checkbox" id="select-all-rows">`),
width: '50px',
formatter: (_, row) => gridjs.html(
`<input type="checkbox" class="formipay-row-checkbox" data-id="${row.cells[0].data}">`
)
},
{
name: formipay_access_page.columns.id,
width: '75px'
},
{
name: formipay_access_page.columns.title,
formatter: (_, row) => {
var html = `
<b>${_}</b><br>
<span class="post-action" style="visibility: hidden;">
<a href="${formipay_access_page.site_url}/wp-admin/post.php?post=${row.cells[0].data}&action=edit">edit</a> | <a href="#" class="delete-access" data-id="${row.cells[0].data}">delete</a> | <a href="#" class="duplicate-access" data-id="${row.cells[0].data}">duplicate</a>
</span>
`;
return gridjs.html(html)
}
},
{
name: formipay_access_page.columns.type,
formatter: (type, row) => {
var html;
if(type == 'Redirect'){
html = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#277aff" d="M11 17H7q-2.075 0-3.537-1.463T2 12t1.463-3.537T7 7h4v2H7q-1.25 0-2.125.875T4 12t.875 2.125T7 15h4zm-3-4v-2h8v2zm5 4v-2h4q1.25 0 2.125-.875T20 12t-.875-2.125T17 9h-4V7h4q2.075 0 3.538 1.463T22 12t-1.463 3.538T17 17z" />
</svg>${type}`;
}else if(type == 'Download') {
html = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#277aff" d="M11 12.15V6.1q-1.9.35-2.95 1.838T7 11h-.5q-1.45 0-2.475 1.025T3 14.5t1.025 2.475T6.5 18h12q1.05 0 1.775-.725T21 15.5t-.725-1.775T18.5 13H17v-2q0-1.2-.55-2.238T15 7V4.675q1.85.875 2.925 2.588T19 11q1.725.2 2.863 1.488T23 15.5q0 1.875-1.312 3.188T18.5 20h-12q-2.275 0-3.887-1.575T1 14.575q0-1.95 1.175-3.475T5.25 9.15q.425-1.8 2.125-3.425T11 4.1q.825 0 1.413.588T13 6.1v6.05l.9-.875q.275-.275.688-.275t.712.3q.275.275.275.7t-.275.7l-2.6 2.6q-.3.3-.7.3t-.7-.3l-2.6-2.6q-.275-.275-.287-.687T8.7 11.3q.275-.275.688-.288t.712.263zm1-1.1" />
</svg>${type}`;
}else if(type == 'Document') {
html = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#277aff" d="M8 13h8v-2H8zm0 3h8v-2H8zm0 3h5v-2H8zm-2 3q-.825 0-1.412-.587T4 20V4q0-.825.588-1.412T6 2h8l6 6v12q0 .825-.587 1.413T18 22zm7-13V4H6v16h12V9zM6 4v5zv16z" />
</svg>${type}`;
}
return gridjs.html(html)
}
},
{
name: formipay_access_page.columns.products,
formatter: (products, row) => {
let html = '';
// Loop through each product in the products array
if(products.length > 0){
products.forEach(product => {
if (product) {
html += `
<span class="product_related">
${product}
</span>
</span>
`;
}
});
}
return gridjs.html(html);
}
},
{
name: formipay_access_page.columns.status,
formatter: (_, row) => gridjs.html(`
<span class="status-label ${_}">${_}</span>
`)
}
],
pagination: {
limit: 10,
server: {
url: (prev, page, limit) => `${prev}&limit=${limit}&offset=${page * limit}`
},
summary: false
},
className: {
table: 'formipay-grid-table'
}
}).render(document.getElementById('formipay-access-items'));
var $tableContainer = $('.formipay-grid-table');
var $deleteBtn = $('#formipay-delete-selected');
function updateDeleteButtonVisibility() {
if ($tableContainer.find('.formipay-row-checkbox:checked').length > 0) {
$deleteBtn.show();
} else {
$deleteBtn.hide();
}
}
// Handle row and "select all" checkbox changes
$tableContainer.on('change', '.formipay-row-checkbox', function() {
updateDeleteButtonVisibility();
});
// Handle row and "select all" checkbox changes
$tableContainer.on('change', '#select-all-rows', function() {
const is_checked = $(this).is(':checked');
$tableContainer.find('.formipay-row-checkbox').prop('checked', is_checked);
updateDeleteButtonVisibility();
});
// Handle delete button click
$deleteBtn.on('click', function() {
var selectedIds = $tableContainer.find('.formipay-row-checkbox:checked').map(function() {
return $(this).data('id');
}).get();
if (selectedIds.length > 0) {
Swal.fire({
icon: 'info',
html: formipay_access_page.modal.bulk_delete.question,
showCancelButton: true,
confirmButtonText: formipay_access_page.modal.bulk_delete.confirmButton,
cancelButtonText: formipay_access_page.modal.bulk_delete.cancelButton
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_access_page.ajax_url,
data: {
action: 'formipay-bulk-delete-access-item',
ids: selectedIds,
_wpnonce: formipay_access_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_table_grid.forceRender();
$tableContainer.find('.formipay-row-checkbox').prop('checked', false);
updateDeleteButtonVisibility();
refresh_table_with_filter();
}
});
}
});
}
});
function refresh_table_with_filter() {
formipay_table_grid.updateConfig({
server: {
url: formipay_access_page.ajax_url+'?action=formipay-tabledata-access-items&post_status='+document.getElementById('post_status').value+'&product='+document.getElementById('products').value+'&orderby='+document.getElementById('orderby').value+'&sort='+document.getElementById('sort_by').value+'&search='+document.getElementById('keyword').value,
then: data => data.results.map(
access => [access.ID, access.ID, access.title, access.type, access.products, access.status]
),
total: data => data.total
}
}).forceRender();
}
$('.form-tool, #post_status').on('change', function(){
refresh_table_with_filter();
});
$(document).on('mouseover', 'td[data-column-id=title]', function(){
$(this).find('.post-action').css('visibility', 'visible');
});
$(document).on('mouseleave', 'td[data-column-id=title]', function(){
$(this).find('.post-action').css('visibility', 'hidden');
});
$(document).on('click', '#add-new-item', async function(e){
e.preventDefault();
const { value: coupon_code } = await Swal.fire({
input: "text",
inputLabel: formipay_access_page.modal.add.title,
showCancelButton: true,
confirmButtonText: formipay_access_page.modal.add.confirmButton,
cancelButtonText: formipay_access_page.modal.add.cancelButton,
reverseButtons: true,
inputValidator: (value) => {
if (!value) {
return formipay_access_page.modal.add.validation;
}
}
}).then((result) => {
/* Read more about isConfirmed, isDenied below, input value is ${coupon_code} */
if (result.isConfirmed && result.value) {
$.ajax({
type: 'post',
url: formipay_access_page.ajax_url,
data: {
action: 'formipay-create-access-item-post',
title: result.value,
nonce: formipay_access_page.nonce
},
success: function (res) {
if(res.success){
window.location.href = res.data.edit_post_url;
}else{
Swal.fire({
html: res.data.message,
icon: 'error'
});
}
}
});
}
});
});
$(document).on('click', '.delete-access', function(e){
e.preventDefault();
var data_id = $(this).attr('data-id');
Swal.fire({
icon: 'info',
html: formipay_access_page.modal.delete.question,
showCancelButton: true,
confirmButtonText: formipay_access_page.modal.delete.confirmButton,
cancelButtonText: formipay_access_page.modal.delete.cancelButton,
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_access_page.ajax_url,
data: {
action: 'formipay-delete-access-item',
id: data_id,
nonce: formipay_access_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_table_grid.forceRender();
}
});
}
});
});
$(document).on('click', '.duplicate-access', function(e){
e.preventDefault();
var data_id = $(this).attr('data-id');
Swal.fire({
icon: 'info',
html: formipay_access_page.modal.duplicate.question,
showCancelButton: true,
confirmButtonText: formipay_access_page.modal.duplicate.confirmButton,
cancelButtonText: formipay_access_page.modal.duplicate.cancelButton,
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_access_page.ajax_url,
data: {
action: 'formipay-duplicate-access-item',
id: data_id,
nonce: formipay_access_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_table_grid.forceRender();
}
});
}
});
});
});

View File

@@ -0,0 +1,346 @@
document.addEventListener('DOMContentLoaded', function () {
const choices = new Choices('#products', {
searchEnabled: true,
searchChoices: false, // Prevent Choices.js from filtering the local list
searchResultLimit: 10, // Optional: Limit visible results
placeholder: true,
placeholderValue: formipay_coupons_page.filter_form.products.placeholder,
noResultsText: formipay_coupons_page.filter_form.products.noresult_text,
itemSelectText: '',
});
const searchInput = document.querySelector('.choices__input--cloned');
let typingTimer;
searchInput.addEventListener('input', function () {
const query = searchInput.value;
if (query.length >= 3) {
clearTimeout(typingTimer);
typingTimer = setTimeout(() => {
fetchChoices(query);
}, 300); // Add a debounce delay
}
});
function fetchChoices(query) {
fetch(formipay_coupons_page.ajax_url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
},
body: new URLSearchParams({
action: 'formipay_coupon_get_products',
search: query,
_wpnonce: formipay_coupons_page.nonce
}),
})
.then((response) => response.json())
.then((data) => {
choices.clearChoices();
choices.setChoices(data, 'value', 'label', false);
})
.catch((error) => console.error('Error:', error));
}
});
jQuery(function($){
let formipay_coupon_table_grid = new gridjs.Grid({
server: {
url: formipay_coupons_page.ajax_url+'?action=formipay-tabledata-coupons&search='+document.getElementById('keyword').value+'&_wpnonce='+formipay_coupons_page.nonce,
then: data => {
if(data.posts_report){
processPostsReport(data.posts_report);
}
return data.results.map(
coupon => [coupon.ID, coupon.ID, coupon.code, coupon.products, coupon.value, coupon.type, coupon.usages, coupon.date_limit, coupon.status, coupon.case_sensitive]
);
},
total: data => data.total
},
columns: [
{
id: 'checkbox',
name: gridjs.html(`<input type="checkbox" id="select-all-rows">`),
width: '50px',
formatter: (_, row) => gridjs.html(
`<input type="checkbox" class="formipay-row-checkbox" data-id="${row.cells[0].data}">`
)
},
{
name: formipay_coupons_page.columns.id,
width: '75px'
},
{
name: formipay_coupons_page.columns.code,
formatter: (_, row) => gridjs.html(`
<b>${_}</b><br>
<span class="post-action" style="visibility: hidden;">
<a href="${formipay_coupons_page.site_url}/wp-admin/post.php?post=${row.cells[0].data}&action=edit">edit</a> | <a href="#" class="delete-coupon" data-id="${row.cells[0].data}">delete</a> | <a href="#" class="duplicate-coupon" data-id="${row.cells[0].data}">duplicate</a>
</span>
`)
},
{
name: formipay_coupons_page.columns.products,
formatter: (products, row) => {
let html = '';
// Loop through each product in the products array
if(products.length > 0){
products.forEach(product => {
if (product) {
const currencyDetails = product.currency.split(':::');
const currencyCode = currencyDetails[0];
const currencySymbol = currencyDetails[2];
html += `
<span class="product_related">
${product.title}<hr>
<span class="country-currency">
${product.flag ? `<img src="${product.flag}" height="18">` : ''}
<span class="currency-in-use">${currencyCode} (${currencySymbol})</span>
</span>
</span>
`;
}
});
}
return gridjs.html(html);
}
},
{
name: formipay_coupons_page.columns.amount,
formatter: (_, row) => numberFormat(_)
},
{
name: formipay_coupons_page.columns.type,
formatter: (_, row) => gridjs.html(`
<span class="type-capsule the-type">${_}</span>
`)
},
{
name: formipay_coupons_page.columns.usages, // { used: 1, limit: 5 }
formatter: (_, row) => gridjs.html(`<span class="coupon-used">${_.used}</span>/<span class="coupon-limit">${_.limit}</span>`) // 1/∞
},
formipay_coupons_page.columns.date_limit,
{
name: formipay_coupons_page.columns.status,
formatter: (_, row) => gridjs.html(`
<span class="status-label ${_.toLowerCase()}">${_}</span>
`)
},
],
pagination: {
limit: 10,
server: {
url: (prev, page, limit) => `${prev}&limit=${limit}&offset=${page * limit}`
},
summary: false
},
className: {
table: 'formipay-grid-table'
}
}).render(document.getElementById('formipay-coupons'));
var $tableContainer = $('.formipay-grid-table');
var $deleteBtn = $('#formipay-delete-selected');
function updateDeleteButtonVisibility() {
if ($tableContainer.find('.formipay-row-checkbox:checked').length > 0) {
$deleteBtn.show();
} else {
$deleteBtn.hide();
}
}
// Handle row and "select all" checkbox changes
$tableContainer.on('change', '.formipay-row-checkbox', function() {
updateDeleteButtonVisibility();
});
// Handle row and "select all" checkbox changes
$tableContainer.on('change', '#select-all-rows', function() {
const is_checked = $(this).is(':checked');
$tableContainer.find('.formipay-row-checkbox').prop('checked', is_checked);
updateDeleteButtonVisibility();
});
// Handle delete button click
$deleteBtn.on('click', function() {
var selectedIds = $tableContainer.find('.formipay-row-checkbox:checked').map(function() {
return $(this).data('id');
}).get();
if (selectedIds.length > 0) {
Swal.fire({
icon: 'info',
html: formipay_coupons_page.modal.bulk_delete.question,
showCancelButton: true,
confirmButtonText: formipay_coupons_page.modal.bulk_delete.confirmButton,
cancelButtonText: formipay_coupons_page.modal.bulk_delete.cancelButton
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_coupons_page.ajax_url,
data: {
action: 'formipay-bulk-delete-coupon',
ids: selectedIds,
_wpnonce: formipay_coupons_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_table_grid.forceRender();
$tableContainer.find('.formipay-row-checkbox').prop('checked', false);
updateDeleteButtonVisibility();
refresh_table_with_filter();
}
});
}
});
}
});
function refresh_table_with_filter() {
formipay_coupon_table_grid.updateConfig({
server: {
url: formipay_coupons_page.ajax_url+'?action=formipay-tabledata-coupons&product='+document.getElementById('products').value+'&search='+document.getElementById('keyword').value+'&_wpnonce='+formipay_coupons_page.nonce,
then: data => data.results.map(
coupon => [coupon.ID, coupon.ID, coupon.code, coupon.products, coupon.value, coupon.type, coupon.usages, coupon.date_limit, coupon.status, coupon.case_sensitive]
),
total: data => data.total
}
}).forceRender();
}
$('.form-tool, #products, #post_status').on('change', function(){
refresh_table_with_filter();
});
$(document).on('mouseover', 'td[data-column-id=couponCode]', function(){
$(this).find('.post-action').css('visibility', 'visible');
});
$(document).on('mouseleave', 'td[data-column-id=couponCode]', function(){
$(this).find('.post-action').css('visibility', 'hidden');
});
$(document).on('input', 'input#swal2-input', function(){
const value = $(this).val();
$(this).val(value.replace(' ', ''));
});
$(document).on('click', '#add-new-coupon', async function(e){
e.preventDefault();
const { value: coupon_code } = await Swal.fire({
input: "text",
inputLabel: formipay_coupons_page.modal.add.title,
showCancelButton: true,
confirmButtonText: formipay_coupons_page.modal.add.confirmButton,
cancelButtonText: formipay_coupons_page.modal.add.cancelButton,
reverseButtons: true,
inputValidator: (value) => {
if (!value) {
return formipay_coupons_page.modal.add.validation;
}
}
}).then((result) => {
/* Read more about isConfirmed, isDenied below, input value is ${coupon_code} */
if (result.isConfirmed && result.value) {
$.ajax({
type: 'post',
url: formipay_coupons_page.ajax_url,
data: {
action: 'formipay-create-coupon-post',
title: result.value,
_wpnonce: formipay_coupons_page.nonce
},
success: function (res) {
if(res.success){
window.location.href = res.data.edit_post_url;
}else{
Swal.fire({
html: res.data.message,
icon: 'error'
});
}
}
});
}
});
});
$(document).on('click', '.delete-coupon', function(e){
e.preventDefault();
var data_id = $(this).attr('data-id');
Swal.fire({
icon: 'info',
html: "Do you want to delete the coupon?",
showCancelButton: true,
confirmButtonText: "Delete Permanently",
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_coupons_page.ajax_url,
data: {
action: 'formipay-delete-coupon',
id: data_id,
_wpnonce: formipay_coupons_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_coupon_table_grid.forceRender();
}
});
}
});
});
$(document).on('click', '.duplicate-coupon', function(e){
e.preventDefault();
var data_id = $(this).attr('data-id');
Swal.fire({
icon: 'info',
html: "Do you want to duplicate the coupon?",
showCancelButton: true,
confirmButtonText: "Confirm",
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_coupons_page.ajax_url,
data: {
action: 'formipay-duplicate-coupon',
id: data_id,
_wpnonce: formipay_coupons_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_coupon_table_grid.forceRender();
}
});
}
});
})
});

View File

@@ -0,0 +1,320 @@
document.getElementById('reset-filter').addEventListener('click', function(){
categoryChoices.removeActiveItems();
currencyChoices.removeActiveItems();
const event = new Event('change', { bubbles: true });
document.getElementById('orderby').value = 'ID';
document.getElementById('sort_by').value = 'desc';
document.getElementById('keyword').value = '';
document.getElementById('keyword').dispatchEvent(event);
});
let formipay_table_grid = new gridjs.Grid({
server: {
url: formipay_forms_page.ajax_url+'?action=formipay-tabledata-forms&post_status='+document.getElementById('post_status').value+'&orderby='+document.getElementById('orderby').value+'&sort='+document.getElementById('sort_by').value+'&search='+document.getElementById('keyword').value+'&_wpnonce='+formipay_forms_page.nonce,
then: data => {
if(data.posts_report){
processPostsReport(data.posts_report);
}
return data.results.map(
form => [form.ID, form.ID, form.title, form.date, form.status]
);
},
total: data => data.total
},
columns: [
{
id: 'checkbox',
name: gridjs.html(`<input type="checkbox" id="select-all-rows">`),
width: '50px',
formatter: (_, row) => gridjs.html(
`<input type="checkbox" class="formipay-row-checkbox" data-id="${row.cells[0].data}">`
)
},
{
name: formipay_forms_page.columns.id,
width: '75px'
},
{
name: formipay_forms_page.columns.title,
formatter: (_, row) => gridjs.html(`
<b>${_}</b><br>
<span class="post-action" style="visibility: hidden;">
<a href="${formipay_forms_page.site_url}/wp-admin/post.php?post=${row.cells[0].data}&action=edit&_wpnonce=${formipay_forms_page.nonce}">edit</a> | <a href="#" class="delete-form" data-id="${row.cells[0].data}">delete</a> | <a href="#" class="duplicate-form" data-id="${row.cells[0].data}">duplicate</a>
</span>
`)
},
{
name: formipay_forms_page.columns.date,
formatter: (_, row) => gridjs.html('<span style="text-wrap: nowrap;">' + _.split(' ').join('</span><br><span style="font-size: smaller;">') + '</span>')
},
{
name: formipay_forms_page.columns.status,
formatter: (_, row) => gridjs.html(`
<span class="status-label ${_}">${_}</span>
`)
},
{
name: formipay_forms_page.columns.shortcode,
formatter: (_, row) => gridjs.html(`
<input class="formipay-form-shortcode" value="[formipay form=${row.cells[0].data}]" disabled>
<button class="copy-shortcode" data-copy="[formipay form=${row.cells[0].data}]">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#b7b7b7" d="M9 18q-.825 0-1.412-.587T7 16V4q0-.825.588-1.412T9 2h9q.825 0 1.413.588T20 4v12q0 .825-.587 1.413T18 18zm0-2h9V4H9zm-4 6q-.825 0-1.412-.587T3 20V6h2v14h11v2zm4-6V4z" />
</svg> ${formipay_forms_page.toast.copy_button.copy}
</button>
`)
},
],
pagination: {
limit: 10,
server: {
url: (prev, page, limit) => `${prev}&limit=${limit}&offset=${page * limit}`
},
summary: false
},
className: {
table: 'formipay-grid-table'
}
}).render(document.getElementById('formipay-forms'));
document.addEventListener('click', function (e) {
const copyButton = e.target.closest('[data-copy]'); // Check if the clicked element or its parent has the data-copy attribute
if (copyButton) {
const textToCopy = copyButton.getAttribute('data-copy');
// Use the Clipboard API to copy text
navigator.clipboard.writeText(textToCopy)
.then(() => {
// Optionally, display a success message
copyButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#000" d="m9.55 18l-5.7-5.7l1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z" />
</svg> ${formipay_forms_page.toast.copy_button.copied}`;
setTimeout(() => {
copyButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#b7b7b7" d="M9 18q-.825 0-1.412-.587T7 16V4q0-.825.588-1.412T9 2h9q.825 0 1.413.588T20 4v12q0 .825-.587 1.413T18 18zm0-2h9V4H9zm-4 6q-.825 0-1.412-.587T3 20V6h2v14h11v2zm4-6V4z" />
</svg> ${formipay_forms_page.toast.copy_button.copy}`; // Reset button text
}, 2000);
Swal.fire({
icon: 'success',
title: formipay_forms_page.toast.copy_button.title,
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
customClass: {
container: 'top-40'
},
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
})
})
.catch((err) => {
console.error('Failed to copy text: ', err);
});
}
});
jQuery(function($){
var $deleteBtn = $('#formipay-delete-selected');
function updateDeleteButtonVisibility() {
if ($(document).find('.formipay-row-checkbox:checked').length > 0) {
$deleteBtn.show();
} else {
$deleteBtn.hide();
}
}
// Handle row and "select all" checkbox changes
$(document).on('change', '.formipay-row-checkbox', function() {
updateDeleteButtonVisibility();
});
// Handle row and "select all" checkbox changes
$(document).on('change', '#select-all-rows', function() {
const is_checked = $(this).is(':checked');
$(document).find('.formipay-row-checkbox').prop('checked', is_checked);
updateDeleteButtonVisibility();
});
// Handle delete button click
$deleteBtn.on('click', function() {
var selectedIds = $(document).find('.formipay-row-checkbox:checked').map(function() {
return $(this).data('id');
}).get();
console.log(selectedIds);
if (selectedIds.length > 0) {
Swal.fire({
icon: 'info',
html: formipay_forms_page.modal.bulk_delete.question,
showCancelButton: true,
confirmButtonText: formipay_forms_page.modal.bulk_delete.confirmButton,
cancelButtonText: formipay_forms_page.modal.bulk_delete.cancelButton
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_forms_page.ajax_url,
data: {
action: 'formipay-bulk-delete-form',
ids: selectedIds,
_wpnonce: formipay_forms_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_table_grid.forceRender();
$(document).find('.formipay-row-checkbox').prop('checked', false);
updateDeleteButtonVisibility();
refresh_table_with_filter();
}
});
}
});
}
});
function refresh_table_with_filter() {
formipay_table_grid.updateConfig({
server: {
url: formipay_forms_page.ajax_url+'?action=formipay-tabledata-forms&post_status='+document.getElementById('post_status').value+'&orderby='+document.getElementById('orderby').value+'&sort='+document.getElementById('sort_by').value+'&search='+document.getElementById('keyword').value+'&_wpnonce='+formipay_forms_page.nonce,
then: data => data.results.map(
form => [form.ID, form.ID, form.title, form.date, form.status]
),
total: data => data.total
}
}).forceRender();
}
$('.form-tool, #post_status').on('change', function(){
refresh_table_with_filter();
});
$(document).on('mouseover', 'td[data-column-id=title]', function(){
$(this).find('.post-action').css('visibility', 'visible');
});
$(document).on('mouseleave', 'td[data-column-id=title]', function(){
$(this).find('.post-action').css('visibility', 'hidden');
});
$(document).on('click', '#add-new-form', async function(e){
e.preventDefault();
const { value: title } = await Swal.fire({
input: "text",
inputLabel: formipay_forms_page.modal.add.title,
showCancelButton: true,
confirmButtonText: formipay_forms_page.modal.add.confirmButton,
cancelButtonText: formipay_forms_page.modal.add.cancelButton,
reverseButtons: true,
inputValidator: (value) => {
if (!value) {
return formipay_forms_page.modal.add.validation;
}
}
}).then((result) => {
/* Read more about isConfirmed, isDenied below, input value is ${coupon_code} */
if (result.isConfirmed && result.value) {
$.ajax({
type: 'post',
url: formipay_forms_page.ajax_url,
data: {
action: 'formipay-create-form-post',
title: result.value,
_wpnonce: formipay_forms_page.nonce
},
success: function (res) {
if(res.success){
window.location.href = res.data.edit_post_url;
}else{
Swal.fire({
html: res.data.message,
icon: 'error'
});
}
}
});
}
});
});
$(document).on('click', '.delete-form', function(e){
e.preventDefault();
var data_id = $(this).attr('data-id');
Swal.fire({
icon: 'info',
html: formipay_forms_page.bulk_delete.question,
showCancelButton: true,
confirmButtonText: formipay_forms_page.delete.confirmButton,
cancelButtonText: formipay_forms_page.delete.cancelButton,
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_forms_page.ajax_url,
data: {
action: 'formipay-delete-form',
id: data_id,
_wpnonce: formipay_forms_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_table_grid.forceRender();
}
});
}
});
});
$(document).on('click', '.duplicate-form', function(e){
e.preventDefault();
var data_id = $(this).attr('data-id');
Swal.fire({
icon: 'info',
html: "Do you want to duplicate the form?",
showCancelButton: true,
confirmButtonText: "Confirm",
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_forms_page.ajax_url,
data: {
action: 'formipay-duplicate-form',
id: data_id,
_wpnonce: formipay_forms_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_table_grid.forceRender();
}
});
}
});
});
});

View File

@@ -0,0 +1,13 @@
jQuery(function($){
$('#wpbody-content').prepend(`
<div class="formipay-screen-menu">
<img src="`+formipay_product_taxonomy_page.site_url+`/wp-content/plugins/formipay/admin/assets/img/formipay-logo-circle-white_256.png" alt="Formipay">
<div class="screen-title">
<h1>`+formipay_product_taxonomy_page.page_title+`</h1>
</div>
</div>
`);
$('form.search-form.wp-clearfix').appendTo('.tablenav.top');
$('.wp-heading-inline').hide();
$(`a[href="edit-tags.php?taxonomy=formipay-product-category&post_type=formipay-product"]`).addClass('current').closest('li').addClass('current');
});

View File

@@ -0,0 +1,371 @@
const categoryChoices = new Choices('#categories', {
searchEnabled: true,
searchChoices: false, // Prevent Choices.js from filtering the local list
searchResultLimit: 10, // Optional: Limit visible results
placeholder: true,
placeholderValue: formipay_products_page.filter_form.categories.placeholder,
noResultsText: formipay_products_page.filter_form.categories.noresult_text,
itemSelectText: '',
allowHTML: true
});
const currencyChoices = new Choices('#currencies', {
searchEnabled: true,
searchChoices: false, // Prevent Choices.js from filtering the local list
searchResultLimit: 10, // Optional: Limit visible results
placeholder: true,
placeholderValue: formipay_products_page.filter_form.currencies.placeholder,
noResultsText: formipay_products_page.filter_form.currencies.noresult_text,
itemSelectText: '',
allowHTML: true
});
const searchInput = document.querySelectorAll('.currency .choices__input--cloned');
let typingTimer;
searchInput[0].addEventListener('input', function () {
const query = this.value;
if (query.length >= 3) {
clearTimeout(typingTimer);
typingTimer = setTimeout(() => {
fetchChoices(query);
}, 300); // Add a debounce delay
}
});
function fetchChoices(query) {
fetch(formipay_products_page.ajax_url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
},
body: new URLSearchParams({
action: 'formipay_product_get_currencies',
search: query,
_wpnonce: formipay_products_page.nonce
}),
})
.then((response) => response.json())
.then((data) => {
currencyChoices.clearChoices();
currencyChoices.setChoices( data, 'value', 'label', true);
})
.catch((error) => console.error('Error:', error));
}
document.getElementById('reset-filter').addEventListener('click', function(){
categoryChoices.removeActiveItems();
currencyChoices.removeActiveItems();
const event = new Event('change', { bubbles: true });
document.getElementById('orderby').value = 'ID';
document.getElementById('sort_by').value = 'desc';
document.getElementById('keyword').value = '';
document.getElementById('keyword').dispatchEvent(event);
});
jQuery(function($){
let formipay_product_table_grid = new gridjs.Grid({
server: {
url: formipay_products_page.ajax_url+'?action=formipay-tabledata-products&post_status='+document.getElementById('post_status').value+'&currency='+document.getElementById('currencies').value+'&category='+document.getElementById('categories').value+'&orderby='+document.getElementById('orderby').value+'&sort='+document.getElementById('sort_by').value+'&search='+document.getElementById('keyword').value+'&_wpnonce='+formipay_products_page.nonce,
then: data => {
if(data.posts_report){
processPostsReport(data.posts_report);
}
return data.results.map(
product => [product.ID, product.ID, product.title, product.price, product.type, product.stock, product.status]
);
},
total: data => data.total
},
columns: [
{
id: 'checkbox',
name: gridjs.html(`<input type="checkbox" id="select-all-rows">`),
width: '50px',
formatter: (_, row) => gridjs.html(
`<input type="checkbox" class="formipay-row-checkbox" data-id="${row.cells[0].data}">`
)
},
{
name: formipay_products_page.columns.id,
width: '75px'
},
{
name: formipay_products_page.columns.title,
formatter: (_, row) => gridjs.html(`
<b>${_}</b><br>
<span class="post-action" style="visibility: hidden;">
<a href="${formipay_products_page.site_url}/wp-admin/post.php?post=${row.cells[0].data}&action=edit">edit</a> | <a href="#" class="delete-product" data-id="${row.cells[0].data}">delete</a> | <a href="#" class="duplicate-product" data-id="${row.cells[0].data}">duplicate</a>
</span>
`)
},
{
name: formipay_products_page.columns.price,
formatter: (_, row) => gridjs.html(`
<span class="price">
<img src="${_.flag}" width="20"> ${_.name}
</span>
`)
},
{
name: formipay_products_page.columns.type
},
{
name: formipay_products_page.columns.stock,
formatter: (_, row) => gridjs.html(`
<span class="type-capsule the-type">${_}</span>
`)
},
{
name: formipay_products_page.columns.status, // { used: 1, limit: 5 }
formatter: (_, row) => gridjs.html(`
<span class="status-label ${_}">${_}</span>
`)
},
],
pagination: {
limit: 10,
server: {
url: (prev, page, limit) => `${prev}&limit=${limit}&offset=${page * limit}`
},
summary: false
},
className: {
table: 'formipay-grid-table'
}
}).render(document.getElementById('formipay-products'));
var $deleteBtn = $('#formipay-delete-selected');
function updateDeleteButtonVisibility() {
if ($(document).find('.formipay-row-checkbox:checked').length > 0) {
$deleteBtn.show();
} else {
$deleteBtn.hide();
}
}
// Handle row and "select all" checkbox changes
$(document).on('change', '.formipay-row-checkbox', function() {
updateDeleteButtonVisibility();
});
// Handle row and "select all" checkbox changes
$(document).on('change', '#select-all-rows', function() {
const is_checked = $(this).is(':checked');
$(document).find('.formipay-row-checkbox').prop('checked', is_checked);
updateDeleteButtonVisibility();
});
// Handle delete button click
$deleteBtn.on('click', function() {
var selectedIds = $(document).find('.formipay-row-checkbox:checked').map(function() {
return $(this).data('id');
}).get();
console.log(selectedIds);
if (selectedIds.length > 0) {
Swal.fire({
icon: 'info',
html: formipay_products_page.modal.bulk_delete.question,
showCancelButton: true,
confirmButtonText: formipay_products_page.modal.bulk_delete.confirmButton,
cancelButtonText: formipay_products_page.modal.bulk_delete.cancelButton
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_products_page.ajax_url,
data: {
action: 'formipay-bulk-delete-product',
ids: selectedIds,
_wpnonce: formipay_products_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
formipay_product_table_grid.forceRender();
$(document).find('.formipay-row-checkbox').prop('checked', false);
updateDeleteButtonVisibility();
refresh_table_with_filter();
}
});
}
});
}
});
function refresh_table_with_filter() {
formipay_product_table_grid.updateConfig({
server: {
url: formipay_products_page.ajax_url+'?action=formipay-tabledata-products&post_status='+document.getElementById('post_status').value+'&currency='+document.getElementById('currencies').value+'&category='+document.getElementById('categories').value+'&orderby='+document.getElementById('orderby').value+'&sort='+document.getElementById('sort_by').value+'&search='+document.getElementById('keyword').value+'&_wpnonce='+formipay_products_page.nonce,
then: data => data.results.map(
product => [product.ID, product.ID, product.title, product.price, product.type, product.stock, product.status]
),
total: data => data.total
}
}).forceRender();
$(document) = $('.formipay-grid-table');
}
$('.form-tool, #post_status').on('change', function(){
refresh_table_with_filter();
});
$(document).on('mouseover', 'td[data-column-id=title]', function(){
$(this).find('.post-action').css('visibility', 'visible');
});
$(document).on('mouseleave', 'td[data-column-id=title]', function(){
$(this).find('.post-action').css('visibility', 'hidden');
});
$(document).on('click', '#add-new-product', async function(e){
e.preventDefault();
var options = [];
$.each(formipay_products_page.modal.form.currency_options, function(value, label){
options.push(`<option value="${value}">${label}</option>`);
});
// Table-based form HTML
const formHtml = `
<input id="swal-input-title" class="swal2-input" placeholder="Product Title">
<input id="swal-input-price" type="number" min="0" class="swal2-input" placeholder="Price">
`;
// Show the SweetAlert2 modal
const { value: title } = await Swal.fire({
input: "text",
inputLabel: formipay_products_page.modal.add.title,
showCancelButton: true,
confirmButtonText: formipay_products_page.modal.add.confirmButton,
cancelButtonText: formipay_products_page.modal.add.cancelButton,
reverseButtons: true,
inputValidator: (value) => {
if (!value) {
return formipay_products_page.modal.add.validation;
}
}
}).then((result) => {
/* Read more about isConfirmed, isDenied below, input value is ${coupon_code} */
if (result.isConfirmed && result.value) {
$.ajax({
type: 'post',
url: formipay_products_page.ajax_url,
data: {
action: 'formipay-create-product-post',
title: result.value,
_wpnonce: formipay_products_page.nonce
},
success: function (res) {
if(res.success){
window.location.href = res.data.edit_post_url;
}else{
Swal.fire({
html: res.data.message,
icon: 'error'
});
}
}
});
}
});
});
$(document).on('click', '.delete-product', function(e){
e.preventDefault();
var data_id = $(this).attr('data-id');
Swal.fire({
icon: 'info',
html: formipay_products_page.modal.delete.question,
showCancelButton: true,
confirmButtonText: formipay_products_page.modal.delete.confirmButton,
cancelButtonText: formipay_products_page.modal.delete.cancelButton,
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_products_page.ajax_url,
data: {
action: 'formipay-delete-product',
id: data_id,
_wpnonce: formipay_products_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
updateDeleteButtonVisibility();
refresh_table_with_filter();
}
});
}
});
});
$(document).on('click', '.duplicate-product', function(e){
e.preventDefault();
var data_id = $(this).attr('data-id');
Swal.fire({
icon: 'info',
html: formipay_products_page.modal.duplicate.question,
showCancelButton: true,
confirmButtonText: formipay_products_page.modal.duplicate.confirmButton,
cancelButtonText: formipay_products_page.modal.duplicate.cancelButton,
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
$.ajax({
type: 'post',
url: formipay_products_page.ajax_url,
data: {
action: 'formipay-duplicate-product',
id: data_id,
_wpnonce: formipay_products_page.nonce
},
success: function (res) {
Swal.fire({
title: res.data.title,
html: res.data.message,
icon: res.data.icon
});
updateDeleteButtonVisibility();
refresh_table_with_filter();
},
error: function(xhr, status, error) {
Swal.fire({
title: 'Error!',
html: xhr.responseText,
icon: 'error',
customClass: {
confirmButton: 'formipay-button-error'
},
allowOutsideClick: false,
allowEscapeKey: false,
showCloseButton: false,
}).then((result) => {
if (result.isConfirmed) {
window.location.reload();
}
});
}
});
}
});
});
});

View File

@@ -0,0 +1,254 @@
[
{"name": "Afghanistan", "code": "AF", "phone": "93"},
{"name": "Albania", "code": "AL", "phone": "355"},
{"name": "Algeria", "code": "DZ", "phone": "213"},
{"name": "American Samoa", "code": "AS", "phone": "1684"},
{"name": "Andorra", "code": "AD", "phone": "376"},
{"name": "Angola", "code": "AO", "phone": "244"},
{"name": "Anguilla", "code": "AI", "phone": "1264"},
{"name": "Antarctica", "code": "AQ", "phone": "672"},
{"name": "Antigua and Barbuda", "code": "AG", "phone": "1268"},
{"name": "Argentina", "code": "AR", "phone": "54"},
{"name": "Armenia", "code": "AM", "phone": "374"},
{"name": "Aruba", "code": "AW", "phone": "297"},
{"name": "Asia/Pacific Region", "code": "AP", "phone": ""},
{"name": "Australia", "code": "AU", "phone": "61"},
{"name": "Austria", "code": "AT", "phone": "43"},
{"name": "Azerbaijan", "code": "AZ", "phone": "994"},
{"name": "Bahamas", "code": "BS", "phone": "1242"},
{"name": "Bahrain", "code": "BH", "phone": "973"},
{"name": "Bangladesh", "code": "BD", "phone": "880"},
{"name": "Barbados", "code": "BB", "phone": "1246"},
{"name": "Belarus", "code": "BY", "phone": "375"},
{"name": "Belgium", "code": "BE", "phone": "32"},
{"name": "Belize", "code": "BZ", "phone": "501"},
{"name": "Benin", "code": "BJ", "phone": "229"},
{"name": "Bermuda", "code": "BM", "phone": "1441"},
{"name": "Bhutan", "code": "BT", "phone": "975"},
{"name": "Bolivia", "code": "BO", "phone": "591"},
{"name": "Bonaire, Sint Eustatius and Saba", "code": "BQ", "phone": "599"},
{"name": "Bosnia and Herzegovina", "code": "BA", "phone": "387"},
{"name": "Botswana", "code": "BW", "phone": "267"},
{"name": "Bouvet Island", "code": "BV", "phone": "55"},
{"name": "Brazil", "code": "BR", "phone": "55"},
{"name": "British Indian Ocean Territory", "code": "IO", "phone": "246"},
{"name": "Brunei Darussalam", "code": "BN", "phone": "673"},
{"name": "Bulgaria", "code": "BG", "phone": "359"},
{"name": "Burkina Faso", "code": "BF", "phone": "226"},
{"name": "Burundi", "code": "BI", "phone": "257"},
{"name": "Cambodia", "code": "KH", "phone": "855"},
{"name": "Cameroon", "code": "CM", "phone": "237"},
{"name": "Canada", "code": "CA", "phone": "1"},
{"name": "Cape Verde", "code": "CV", "phone": "238"},
{"name": "Cayman Islands", "code": "KY", "phone": "1345"},
{"name": "Central African Republic", "code": "CF", "phone": "236"},
{"name": "Chad", "code": "TD", "phone": "235"},
{"name": "Chile", "code": "CL", "phone": "56"},
{"name": "China", "code": "CN", "phone": "86"},
{"name": "Christmas Island", "code": "CX", "phone": "61"},
{"name": "Cocos (Keeling) Islands", "code": "CC", "phone": "672"},
{"name": "Colombia", "code": "CO", "phone": "57"},
{"name": "Comoros", "code": "KM", "phone": "269"},
{"name": "Congo", "code": "CG", "phone": "242"},
{"name": "Congo, The Democratic Republic of the", "code": "CD", "phone": "242"},
{"name": "Cook Islands", "code": "CK", "phone": "682"},
{"name": "Costa Rica", "code": "CR", "phone": "506"},
{"name": "Croatia", "code": "HR", "phone": "385"},
{"name": "Cuba", "code": "CU", "phone": "53"},
{"name": "Curaçao", "code": "CW", "phone": "599"},
{"name": "Cyprus", "code": "CY", "phone": "357"},
{"name": "Czech Republic", "code": "CZ", "phone": "420"},
{"name": "Côte d'Ivoire", "code": "CI", "phone": "225"},
{"name": "Denmark", "code": "DK", "phone": "45"},
{"name": "Djibouti", "code": "DJ", "phone": "253"},
{"name": "Dominica", "code": "DM", "phone": "1767"},
{"name": "Dominican Republic", "code": "DO", "phone": "1809"},
{"name": "Ecuador", "code": "EC", "phone": "593"},
{"name": "Egypt", "code": "EG", "phone": "20"},
{"name": "El Salvador", "code": "SV", "phone": "503"},
{"name": "Equatorial Guinea", "code": "GQ", "phone": "240"},
{"name": "Eritrea", "code": "ER", "phone": "291"},
{"name": "Estonia", "code": "EE", "phone": "372"},
{"name": "Ethiopia", "code": "ET", "phone": "251"},
{"name": "Falkland Islands (Malvinas)", "code": "FK", "phone": "500"},
{"name": "Faroe Islands", "code": "FO", "phone": "298"},
{"name": "Fiji", "code": "FJ", "phone": "679"},
{"name": "Finland", "code": "FI", "phone": "358"},
{"name": "France", "code": "FR", "phone": "33"},
{"name": "French Guiana", "code": "GF", "phone": "594"},
{"name": "French Polynesia", "code": "PF", "phone": "689"},
{"name": "French Southern Territories", "code": "TF", "phone": "262"},
{"name": "Gabon", "code": "GA", "phone": "241"},
{"name": "Gambia", "code": "GM", "phone": "220"},
{"name": "Georgia", "code": "GE", "phone": "995"},
{"name": "Germany", "code": "DE", "phone": "49"},
{"name": "Ghana", "code": "GH", "phone": "233"},
{"name": "Gibraltar", "code": "GI", "phone": "350"},
{"name": "Greece", "code": "GR", "phone": "30"},
{"name": "Greenland", "code": "GL", "phone": "299"},
{"name": "Grenada", "code": "GD", "phone": "1473"},
{"name": "Guadeloupe", "code": "GP", "phone": "590"},
{"name": "Guam", "code": "GU", "phone": "1671"},
{"name": "Guatemala", "code": "GT", "phone": "502"},
{"name": "Guernsey", "code": "GG", "phone": "44"},
{"name": "Guinea", "code": "GN", "phone": "224"},
{"name": "Guinea-Bissau", "code": "GW", "phone": "245"},
{"name": "Guyana", "code": "GY", "phone": "592"},
{"name": "Haiti", "code": "HT", "phone": "509"},
{"name": "Heard Island and Mcdonald Islands", "code": "HM", "phone": "0"},
{"name": "Holy See (Vatican City State)", "code": "VA", "phone": "39"},
{"name": "Honduras", "code": "HN", "phone": "504"},
{"name": "Hong Kong", "code": "HK", "phone": "852"},
{"name": "Hungary", "code": "HU", "phone": "36"},
{"name": "Iceland", "code": "IS", "phone": "354"},
{"name": "India", "code": "IN", "phone": "91"},
{"name": "Indonesia", "code": "ID", "phone": "62"},
{"name": "Iran, Islamic Republic Of", "code": "IR", "phone": "98"},
{"name": "Iraq", "code": "IQ", "phone": "964"},
{"name": "Ireland", "code": "IE", "phone": "353"},
{"name": "Isle of Man", "code": "IM", "phone": "44"},
{"name": "Israel", "code": "IL", "phone": "972"},
{"name": "Italy", "code": "IT", "phone": "39"},
{"name": "Jamaica", "code": "JM", "phone": "1876"},
{"name": "Japan", "code": "JP", "phone": "81"},
{"name": "Jersey", "code": "JE", "phone": "44"},
{"name": "Jordan", "code": "JO", "phone": "962"},
{"name": "Kazakhstan", "code": "KZ", "phone": "7"},
{"name": "Kenya", "code": "KE", "phone": "254"},
{"name": "Kiribati", "code": "KI", "phone": "686"},
{"name": "Korea, Republic of", "code": "KR", "phone": "82"},
{"name": "Kuwait", "code": "KW", "phone": "965"},
{"name": "Kyrgyzstan", "code": "KG", "phone": "996"},
{"name": "Laos", "code": "LA", "phone": "856"},
{"name": "Latvia", "code": "LV", "phone": "371"},
{"name": "Lebanon", "code": "LB", "phone": "961"},
{"name": "Lesotho", "code": "LS", "phone": "266"},
{"name": "Liberia", "code": "LR", "phone": "231"},
{"name": "Libyan Arab Jamahiriya", "code": "LY", "phone": "218"},
{"name": "Liechtenstein", "code": "LI", "phone": "423"},
{"name": "Lithuania", "code": "LT", "phone": "370"},
{"name": "Luxembourg", "code": "LU", "phone": "352"},
{"name": "Macao", "code": "MO", "phone": "853"},
{"name": "Madagascar", "code": "MG", "phone": "261"},
{"name": "Malawi", "code": "MW", "phone": "265"},
{"name": "Malaysia", "code": "MY", "phone": "60"},
{"name": "Maldives", "code": "MV", "phone": "960"},
{"name": "Mali", "code": "ML", "phone": "223"},
{"name": "Malta", "code": "MT", "phone": "356"},
{"name": "Marshall Islands", "code": "MH", "phone": "692"},
{"name": "Martinique", "code": "MQ", "phone": "596"},
{"name": "Mauritania", "code": "MR", "phone": "222"},
{"name": "Mauritius", "code": "MU", "phone": "230"},
{"name": "Mayotte", "code": "YT", "phone": "269"},
{"name": "Mexico", "code": "MX", "phone": "52"},
{"name": "Micronesia, Federated States of", "code": "FM", "phone": "691"},
{"name": "Moldova, Republic of", "code": "MD", "phone": "373"},
{"name": "Monaco", "code": "MC", "phone": "377"},
{"name": "Mongolia", "code": "MN", "phone": "976"},
{"name": "Montenegro", "code": "ME", "phone": "382"},
{"name": "Montserrat", "code": "MS", "phone": "1664"},
{"name": "Morocco", "code": "MA", "phone": "212"},
{"name": "Mozambique", "code": "MZ", "phone": "258"},
{"name": "Myanmar", "code": "MM", "phone": "95"},
{"name": "Namibia", "code": "NA", "phone": "264"},
{"name": "Nauru", "code": "NR", "phone": "674"},
{"name": "Nepal", "code": "NP", "phone": "977"},
{"name": "Netherlands", "code": "NL", "phone": "31"},
{"name": "Netherlands Antilles", "code": "AN", "phone": "599"},
{"name": "New Caledonia", "code": "NC", "phone": "687"},
{"name": "New Zealand", "code": "NZ", "phone": "64"},
{"name": "Nicaragua", "code": "NI", "phone": "505"},
{"name": "Niger", "code": "NE", "phone": "227"},
{"name": "Nigeria", "code": "NG", "phone": "234"},
{"name": "Niue", "code": "NU", "phone": "683"},
{"name": "Norfolk Island", "code": "NF", "phone": "672"},
{"name": "North Korea", "code": "KP", "phone": "850"},
{"name": "North Macedonia", "code": "MK", "phone": "389"},
{"name": "Northern Mariana Islands", "code": "MP", "phone": "1670"},
{"name": "Norway", "code": "NO", "phone": "47"},
{"name": "Oman", "code": "OM", "phone": "968"},
{"name": "Pakistan", "code": "PK", "phone": "92"},
{"name": "Palau", "code": "PW", "phone": "680"},
{"name": "Palestinian Territory, Occupied", "code": "PS", "phone": "970"},
{"name": "Panama", "code": "PA", "phone": "507"},
{"name": "Papua New Guinea", "code": "PG", "phone": "675"},
{"name": "Paraguay", "code": "PY", "phone": "595"},
{"name": "Peru", "code": "PE", "phone": "51"},
{"name": "Philippines", "code": "PH", "phone": "63"},
{"name": "Pitcairn Islands", "code": "PN", "phone": "64"},
{"name": "Poland", "code": "PL", "phone": "48"},
{"name": "Portugal", "code": "PT", "phone": "351"},
{"name": "Puerto Rico", "code": "PR", "phone": "1787"},
{"name": "Qatar", "code": "QA", "phone": "974"},
{"name": "Reunion", "code": "RE", "phone": "262"},
{"name": "Romania", "code": "RO", "phone": "40"},
{"name": "Russian Federation", "code": "RU", "phone": "7"},
{"name": "Rwanda", "code": "RW", "phone": "250"},
{"name": "Saint Barthélemy", "code": "BL", "phone": "590"},
{"name": "Saint Helena", "code": "SH", "phone": "290"},
{"name": "Saint Kitts and Nevis", "code": "KN", "phone": "1869"},
{"name": "Saint Lucia", "code": "LC", "phone": "1758"},
{"name": "Saint Martin", "code": "MF", "phone": "590"},
{"name": "Saint Pierre and Miquelon", "code": "PM", "phone": "508"},
{"name": "Saint Vincent and the Grenadines", "code": "VC", "phone": "1784"},
{"name": "Samoa", "code": "WS", "phone": "684"},
{"name": "San Marino", "code": "SM", "phone": "378"},
{"name": "Sao Tome and Principe", "code": "ST", "phone": "239"},
{"name": "Saudi Arabia", "code": "SA", "phone": "966"},
{"name": "Senegal", "code": "SN", "phone": "221"},
{"name": "Serbia", "code": "RS", "phone": "381"},
{"name": "Serbia and Montenegro", "code": "CS", "phone": "381"},
{"name": "Seychelles", "code": "SC", "phone": "248"},
{"name": "Sierra Leone", "code": "SL", "phone": "232"},
{"name": "Singapore", "code": "SG", "phone": "65"},
{"name": "Sint Maarten", "code": "SX", "phone": "1"},
{"name": "Slovakia", "code": "SK", "phone": "421"},
{"name": "Slovenia", "code": "SI", "phone": "386"},
{"name": "Solomon Islands", "code": "SB", "phone": "677"},
{"name": "Somalia", "code": "SO", "phone": "252"},
{"name": "South Africa", "code": "ZA", "phone": "27"},
{"name": "South Georgia and the South Sandwich Islands", "code": "GS", "phone": "500"},
{"name": "South Sudan", "code": "SS", "phone": "211"},
{"name": "Spain", "code": "ES", "phone": "34"},
{"name": "Sri Lanka", "code": "LK", "phone": "94"},
{"name": "Sudan", "code": "SD", "phone": "249"},
{"name": "Suriname", "code": "SR", "phone": "597"},
{"name": "Svalbard and Jan Mayen", "code": "SJ", "phone": "47"},
{"name": "Swaziland", "code": "SZ", "phone": "268"},
{"name": "Sweden", "code": "SE", "phone": "46"},
{"name": "Switzerland", "code": "CH", "phone": "41"},
{"name": "Syrian Arab Republic", "code": "SY", "phone": "963"},
{"name": "Taiwan", "code": "TW", "phone": "886"},
{"name": "Tajikistan", "code": "TJ", "phone": "992"},
{"name": "Tanzania, United Republic of", "code": "TZ", "phone": "255"},
{"name": "Thailand", "code": "TH", "phone": "66"},
{"name": "Timor-Leste", "code": "TL", "phone": "670"},
{"name": "Togo", "code": "TG", "phone": "228"},
{"name": "Tokelau", "code": "TK", "phone": "690"},
{"name": "Tonga", "code": "TO", "phone": "676"},
{"name": "Trinidad and Tobago", "code": "TT", "phone": "1868"},
{"name": "Tunisia", "code": "TN", "phone": "216"},
{"name": "Turkey", "code": "TR", "phone": "90"},
{"name": "Turkmenistan", "code": "TM", "phone": "7370"},
{"name": "Turks and Caicos Islands", "code": "TC", "phone": "1649"},
{"name": "Tuvalu", "code": "TV", "phone": "688"},
{"name": "Uganda", "code": "UG", "phone": "256"},
{"name": "Ukraine", "code": "UA", "phone": "380"},
{"name": "United Arab Emirates", "code": "AE", "phone": "971"},
{"name": "United Kingdom", "code": "GB", "phone": "44"},
{"name": "United States", "code": "US", "phone": "1"},
{"name": "United States Minor Outlying Islands", "code": "UM", "phone": "1"},
{"name": "Uruguay", "code": "UY", "phone": "598"},
{"name": "Uzbekistan", "code": "UZ", "phone": "998"},
{"name": "Vanuatu", "code": "VU", "phone": "678"},
{"name": "Venezuela", "code": "VE", "phone": "58"},
{"name": "Vietnam", "code": "VN", "phone": "84"},
{"name": "Virgin Islands, British", "code": "VG", "phone": "1284"},
{"name": "Virgin Islands, U.S.", "code": "VI", "phone": "1340"},
{"name": "Wallis and Futuna", "code": "WF", "phone": "681"},
{"name": "Western Sahara", "code": "EH", "phone": "212"},
{"name": "Yemen", "code": "YE", "phone": "967"},
{"name": "Zambia", "code": "ZM", "phone": "260"},
{"name": "Zimbabwe", "code": "ZW", "phone": "263"},
{"name": "Åland Islands", "code": "AX", "phone": "358"}
]

File diff suppressed because one or more lines are too long

1099
admin/assets/json/flags.json Normal file

File diff suppressed because it is too large Load Diff

885
admin/functions.php Normal file
View File

@@ -0,0 +1,885 @@
<?php
function formipay_field_type_collection() {
$types = [
'text' => __( 'Text', 'formipay' ),
'url' => __( 'URL', 'formipay' ),
'email' => __( 'Email', 'formipay' ),
'tel' => __( 'Telephone', 'formipay' ),
'number' => __( 'Number', 'formipay' ),
'date' => __( 'Date', 'formipay' ),
'datetime' => __( 'Date & Time', 'formipay' ),
'color' => __( 'Number', 'formipay' ),
'select' => __( 'Select Dropdown', 'formipay' ),
'checkbox' => __( 'Checkbox', 'formipay' ),
'radio' => __( 'Radio', 'formipay' ),
'hidden' => __( 'Hidden', 'formipay' ),
'textarea' => __( 'Textarea', 'formipay' ),
'divider' => __( 'Divider', 'formipay' ),
'page_break' => __( 'Page Break', 'formipay' ),
'country_list' => __( 'Preset: Country List', 'formipay' )
];
$types = apply_filters( 'formipay/form-config/field-type', $types);
return $types;
}
function formipay_currency_array() {
$json = file_get_contents(FORMIPAY_PATH . 'admin/assets/json/currencies.json');
$array = json_decode($json, true);
return $array;
}
function formipay_country_array() {
$json = file_get_contents(FORMIPAY_PATH . 'admin/assets/json/country.json');
$array = json_decode($json, true);
return $array;
}
function formipay_get_flag_by_currency($currency) {
if(strpos($currency, ':::')){
$currency = explode(':::', $currency);
$currency = $currency[0];
}
$json = file_get_contents(FORMIPAY_PATH . 'admin/assets/json/flags.json');
$array = json_decode($json, true);
foreach($array as $country){
if($currency == $country['code']){
return $country['flag'];
}
}
return false;
}
function formipay_price_format($num = 0, $post_id = 0){
$decimal_digits = 2;
$decimal_symbol = '.';
$thousand_separator_symbol = ',';
if($post_id > 0 ){
$currency_data = explode(':::', get_post_meta($post_id, 'product_currency', true));
$decimal_digits = get_post_meta($post_id, 'product_currency_decimal_digits', true);
$decimal_symbol = get_post_meta($post_id, 'product_currency_decimal_symbol', true);
$thousand_separator_symbol = get_post_meta($post_id, 'product_currency_thousand_separator', true);
if(isset($currency_data[2]) && !empty($currency_data[2])){
$currency = $currency_data[2];
}else{
$currency = $currency_data[0];
}
return $currency .' '. number_format(floatval($num), intval($decimal_digits), $decimal_symbol, $thousand_separator_symbol);
}
return number_format(floatval($num), intval($decimal_digits), $decimal_symbol, $thousand_separator_symbol);
}
function formipay_currency_as_options($currency_code = '') {
$currencies = formipay_currency_array();
$result = [];
foreach($currencies as $currency){
$code = $currency['code'];
$currency_id = implode(':::', $currency);
if('' !== $currency_code && $code == $currency_code){
$result = $currency_id;
break;
}
$result[$currency_id] = ucwords($currency['name']);
}
return $result;
}
function formipay_post_currency($post_id){
$currency = formipay_get_post_meta($post_id, 'product_currency');
$currency = explode(':::', $currency);
$currency_symbol = $currency[0];
if(isset($currency[2]) && '' !== $currency[2]){
$currency_symbol = $currency[2];
}
return $currency_symbol;
}
function formipay_get_currency_data_by_value($value, $data='') {
$currency = explode(':::', $value);
switch ($data) {
case 'title':
$output = $currency[1];
break;
case 'symbol':
$output = $currency[0];
// if(isset($currency[2]) && '' !== $currency[2] && false !== boolval($currency[2])){
// $output = $currency[2];
// }
break;
default:
$output = $value;
break;
}
return $output;
}
function formipay_default_currency($return='raw') {
$formipay_settings = get_option('formipay_settings');
$default_currency = $formipay_settings['payment_default_currency'];
switch ($return) {
case 'symbol':
$output = formipay_get_currency_data_by_value($default_currency, 'symbol');
break;
case 'title':
$output = formipay_get_currency_data_by_value($default_currency, 'title');
break;
case 'decimal_digits':
$output = $formipay_settings['payment_default_currency_decimal_digits'];
break;
case 'decimal_symbol':
$output = $formipay_settings['payment_default_currency_decimal_symbol'];
break;
case 'thousand_separator':
$output = $formipay_settings['payment_default_currency_thousand_separator'];
break;
default:
$output = $formipay_settings['payment_default_currency'];
break;
}
return $output;
}
function formipay_get_post_meta($post_id, $metakey) {
$value = get_post_meta($post_id, $metakey, true);
if(!empty($value) && false !== $value && '' !== $value){
return $value;
}
return false;
}
function formipay_order_status_list() {
$statuses = array(
'on-hold' => 'On Hold',
'payment-confirm' => 'Payment Confirmed',
'in-progress' => 'In Progress',
'shipping' => 'Shipping',
'completed' => 'Completed',
'failed' => 'Failed',
'refunded' => 'Refunded',
'cancelled' => 'Cancelled'
);
return $statuses;
}
function formipay_get_order($order_id) {
$formipay_settings = get_option('formipay_settings');
$order = apply_filters( 'formipay/order/get', false, $order_id );
$order_data = [];
if(false !== $order){
foreach($order as $key => $data){
$order_data[$key] = maybe_unserialize( $data );
if($key == 'items'){
foreach($order_data[$key] as $index => $item){
$order_data[$key][$index]['subtotal_formatted'] = formipay_price_format($item['subtotal'], $order_data['form_id']);
}
}
}
$order_data['total_formatted'] = formipay_price_format($order_data['total'], $order_data['form_id']);
// Form Submission Data Process to Readable
if(!empty($order_data['form_data'])){
$field_types = formipay_field_type_collection();
$form_field = get_post_meta($order_data['form_id'], 'formipay_settings', true);
$form_field = $form_field['fields'];
$all_fields = [];
foreach($form_field as $key => $field){
if(array_key_exists($field['field_type'], $field_types)){
$skip = false;
if(in_array($field['field_type'], ['divider', 'page_break'])){
$options = $field['field_options'];
if(!empty($options)){
foreach($options as $option){
if(!empty($option['amount'])){
$skip = true;
}
}
}
}
if(false == $skip){
$all_fields[$key] = $field;
}
}
}
$proceed_form_data = [];
foreach($order_data['form_data'] as $name => $value){
switch ($name) {
case 'qty':
$label = esc_html__( 'Quantity', 'formipay' );
break;
case 'payment':
$label = esc_html__( 'Payment', 'formipay' );
break;
case 'coupon_code':
$label = esc_html__( 'Coupon Code', 'formipay' );
break;
case 'payment_gateway':
$label = esc_html__( 'Payment Gateway', 'formipay' );
break;
default:
if(!empty($all_fields[$name.'_config'])){
$label = $all_fields[$name.'_config']['label'];
}else{
$label = '';
}
break;
}
$data_value = $value;
if(is_array($value)){
$data_value = $value['label'] !== 'undefined' ? $value['label'] : $value['value'];
}
if($name == 'payment'){
if(strpos($value, ':::') !== false){
$value = explode(':::', $value);
$data_value = isset($value[1]) ? $value[1] : $value[0];
// If this is bank_transfer
if(
$value[0] == 'bank_transfer' &&
isset($value[1]) &&
strpos($value[1], '-') !== false
) {
$bank_account = explode('-', $value[1]);
$bank_account_index = intval($bank_account[1]) + 1;
// translators: %d is the bank account index number.
$bank_label = $bank_account[0] . ' (' . sprintf( __( 'Bank Accounts #%d', 'formipay' ), $bank_account_index) . ')';
$data_value = $bank_label;
}
}
}
$proceed_form_data[$name] = [
'name' => $name,
'value' => $data_value !== '' ? $data_value : '-',
'label' => $label
];
}
$order_data['form_data'] = $proceed_form_data;
}
$thankyou_link = site_url( $formipay_settings['thankyou_link'] . '/' . base64_encode( $order_data['form_id'] . ':::' . $order_id ) );
$order_data['thankyou'] = [
'link' => $thankyou_link,
'pass_method' => !empty($order_data['meta_data']['access_method']) ? $order_data['meta_data']['access_method'] : 'magic_link',
'pass_word' => (!empty($order_data['meta_data']['access_password']) && !empty($order_data['meta_data']['access_method'])) ? $order_data['meta_data']['access_password'] : formipay_generate_password(),
];
if(!empty($order_data['meta_data'])){
$proceed_meta_data = [];
foreach($order_data['meta_data'] as $name => $value){
$label = explode('_', $name);
$__label = [];
foreach($label as $_label){
if(strlen($_label) <= 3){
$__label[] = strtoupper($_label);
}else{
$__label[] = ucfirst($_label);
}
}
$proceed_meta_data[$name] = [
'label' => implode(' ', $__label),
'name' => $name,
'value' => $value !== '' ? $value : '-'
];
}
$order_data['meta_data'] = $proceed_meta_data;
}
// Payment Data Process to Readable
if(!empty($order['payment_gateway'])){
$trx_data = formipay_get_payment_data($order_id, $order['payment_gateway']);
if(false !== $trx_data) {
$order_data['transaction'] = $trx_data;
}
$timeline = [
[
'time' => $order['created_date'],
// translators: %s is the payment gateway name.
'activity' => sprintf( __( 'Order created via %s', 'formipay'), ucwords(str_replace( '_', ' ', $order['payment_gateway'])) ),
'attachment' => 'none'
]
];
if(!empty($trx_data)){
foreach($trx_data as $trx){
if($order['payment_gateway'] == 'bank_transfer' && !empty($trx['meta_data']['transfer_receipt'])) {
$timeline[] = [
'time' => formipay_date($trx['meta_data']['transfer_receipt']['time']),
'activity' => __( 'Payment confirmation by uploading transfer receipt.', 'formipay' ),
'attachment' => !empty($trx['meta_data']['transfer_receipt']['attachment_url']) ? $trx['meta_data']['transfer_receipt']['attachment_url'] : 'none'
];
}
if($order['payment_gateway'] == 'paypal' && !empty($trx['meta_data']) && $trx['meta_data']['status'] == 'COMPLETED') {
$timeline[] = [
'time' => formipay_date($trx['meta_data']['update_time']),
'activity' => __( 'Payment completed via Paypal.', 'formipay' ),
'attachment' => 'none'
];
}
}
}
$timeline = apply_filters( 'formipay/order/transaction/timeline', $timeline, $order_id );
$order_data['transaction_timeline'] = $timeline;
}
$notif_data = formipay_get_notification_data($order_id);
if(false !== $notif_data) {
$order_data['notification'] = $notif_data;
}
}
return $order_data;
}
function formipay_get_payment_data($order_id, $payment_gateway) {
global $wpdb;
if($payment_gateway !== 'cod'){
$table_name = $wpdb->prefix . 'formipay_'.$payment_gateway.'_trx';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$get = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM %i WHERE `order_id` = %d", $table_name, $order_id), ARRAY_A
);
$trx_data = [];
if(false !== $get){
foreach($get as $index => $row){
foreach($row as $key => $value){
$trx_data[$index][$key] = maybe_unserialize( $value );
}
}
}
return !empty($trx_data) ? $trx_data : $get;
}
return [];
}
function formipay_get_notification_data($order_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'formipay_notification_log';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$get = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM %i WHERE `order_id` = %d", $table_name, $order_id), ARRAY_A
);
$notif_data = [];
if(false !== $get){
foreach($get as $row_key => $row){
foreach($row as $key => $value){
$notif_data[$row_key][$key] = maybe_unserialize( $value );
}
$notif_data[$row_key]['recipient'] = $notif_data[$row_key]['notification_data']['to'];
$notif_data[$row_key]['title'] = $notif_data[$row_key]['notification_data']['subject'];
switch ($notif_data[$row_key]['recipient_type']) {
case 'email':
$icon = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<g fill="#fff">
<path d="M22 7.535V17a3 3 0 0 1-2.824 2.995L19 20H5a3 3 0 0 1-2.995-2.824L2 17V7.535l9.445 6.297l.116.066a1 1 0 0 0 .878 0l.116-.066z" />
<path d="M19 4c1.08 0 2.027.57 2.555 1.427L12 11.797l-9.555-6.37a3 3 0 0 1 2.354-1.42L5 4z" />
</g>
</svg>';
break;
case 'waba':
case 'whatsapp':
$icon = '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#fff" d="M18.497 4.409a10 10 0 0 1-10.36 16.828l-.223-.098l-4.759.849l-.11.011a1 1 0 0 1-.11 0l-.102-.013l-.108-.024l-.105-.037l-.099-.047l-.093-.058l-.014-.011l-.012-.007l-.086-.073l-.077-.08l-.067-.088l-.056-.094l-.034-.07l-.04-.108l-.028-.128l-.012-.102a1 1 0 0 1 0-.125l.012-.1l.024-.11l.045-.122l1.433-3.304l-.009-.014A10 10 0 0 1 5.056 4.83l.215-.203a10 10 0 0 1 13.226-.217M9.5 7.5A1.5 1.5 0 0 0 8 9v1a6 6 0 0 0 6 6h1a1.5 1.5 0 0 0 0-3h-1l-.144.007a1.5 1.5 0 0 0-1.128.697l-.042.074l-.022-.007a4.01 4.01 0 0 1-2.435-2.435l-.008-.023l.075-.041A1.5 1.5 0 0 0 11 10V9a1.5 1.5 0 0 0-1.5-1.5" />
</svg>';
break;
default:
$icon = '';
break;
}
}
}
return !empty($notif_data) ? $notif_data : $get;
}
function formipay_update_order_status($args) {
$data = wp_parse_args( $args, [
'form_id' => 0,
'order_id' => 0,
'payment_gateway' => '',
'status' => 'on-hold'
] );
$order_id = intval($data['order_id']);
$order = new Formipay_Order();
// $get = $order->get($order_id);
$update = $order->update($order_id, [
'status' => $data['status']
]);
if(is_wp_error( $update )){
$response = [
'valid' => false,
'message' => str_replace(
[
'{{order_id}}', '{{system_error_message}}'
],
[
$order_id, $update->get_error_message()
],
formipay_get_post_meta($data['form_id'], $data['payment_gateway'] . '_confirmation_message_error')
)
];
}else{
$response = [
'valid' => true,
'message' => str_replace(
'{{order_id}}',
$order_id,
formipay_get_post_meta($data['form_id'], $data['payment_gateway'] . '_confirmation_message_success')
)
];
}
return $response;
}
function formipay_date($format = '', $date = '') {
if ($format == '') {
$format = get_option('date_format') . ' ' . get_option('time_format');
}
$timezone = new DateTimeZone(wp_timezone_string());
if (empty($date)) {
$datetime = new DateTime('now', $timezone);
} else {
// Detect if $date is a timestamp (integer or numeric string)
if (is_numeric($date) && (int)$date == $date) {
// Create DateTime from timestamp
$datetime = new DateTime('@' . $date); // UTC by default
$datetime->setTimezone($timezone);
} else {
// Create DateTime from date string in UTC
$datetime = new DateTime($date, new DateTimeZone('UTC'));
$datetime->setTimezone($timezone);
}
}
if ($format === 'timestamp') {
return (int) $datetime->format('U');
}
return $datetime->format($format);
}
function formipay_editor_hints() {
$hints = [
'buyer_name' => __( 'Buyer Name', 'formipay' ),
'product_name' => __( 'Product Name', 'formipay' ),
'order_id' => __( 'Order ID', 'formipay' ),
'order_date' => __( 'Order Date', 'formipay' ),
'order_total' => __( 'Order Total', 'formipay' ),
'order_status' => __( 'Order Status', 'formipay' ),
'order_details' => __( 'Order Details', 'formipay' ),
'form_submission' => __( 'All Field Submissions', 'formipay' ),
'payment_details' => __( 'Payment Details', 'formipay' )
];
$hints = apply_filters( 'formipay/form-config/notification/hints', $hints );
return $hints;
}
function formipay_is_HTML($string){
return $string !== wp_strip_all_tags($string) ? true : false ;
}
function allow_style_attribute_for_all_tags($content) {
// Get all standard HTML tags
$allowed_tags = wp_kses_allowed_html('post');
// Iterate over the allowed tags and add 'style' attribute to each
foreach ($allowed_tags as $tag => $attributes) {
$allowed_tags[$tag]['style'] = array(); // Allow 'style' attribute
}
// Sanitize the content with the updated allowed tags
return wp_kses($content, $allowed_tags);
}
function formipay_isPopup($post_id) {
if(formipay_get_post_meta($post_id, 'form_display_as') == 'popup'){
return true;
}
return false;
}
function formipay_filesize($attachment_id) {
$metadata = wp_get_attachment_metadata($attachment_id);
$fileSize = $metadata['filesize'];
$sizeLabels = ['B', 'KB', 'MB', 'GB'];
$index = 0;
while ($fileSize >= 1024 && $index < count($sizeLabels) - 1) {
$fileSize /= 1024;
$index++;
}
return number_format($fileSize, 2) . ' ' . $sizeLabels[$index];
}
function formipay_attachment_icon($attachment_id = 0){
if($attachment_id > 0){
$get_attach = get_post($attachment_id);
$mime = $get_attach->post_mime_type;
$mime = explode('/', $mime);
$type = $mime[1];
switch ($type) {
case 'zip':
$icon = '<i class="bi bi-file-earmark-zip formipay-download-icon"></i>';
break;
default:
$icon = '<i class="bi bi-filetype-'.$type.' formipay-download-icon"></i>';
break;
}
}else{
$icon = '<i class="bi bi-link-45deg formipay-download-icon"></i>';
}
return $icon;
}
function order_meta_fields() {
return array(
'user_id', 'session_id', 'referrer', 'page_url', 'timestamp', 'utm_source', 'utm_medium', 'utm_campaign', 'ip_address', 'user_agent'
);
}
function formipay_get_coupon_id_by_code($code, $form_id) {
global $wpdb;
// Validate input early
if (empty($code) || empty($form_id)) {
return false;
}
// Get coupon by code directly using title match
$coupon_post = false;
$query = new WP_Query([
'post_type' => 'formipay-coupon',
'title' => $code,
'post_status' => 'publish',
'posts_per_page' => 1,
'fields' => 'all', // or 'ids' if you only need the ID
]);
if (!empty($query->posts)) {
$coupon_post = $query->posts[0]; // Returns the post object
}
if (!$coupon_post || $coupon_post->post_status !== 'publish') {
return false;
}
$coupon_id = $coupon_post->ID;
// Check active status first
if (formipay_get_post_meta($coupon_id, 'active') !== 'on') {
return false;
}
// Check form restrictions using meta query
$allowed_forms = formipay_get_post_meta($coupon_id, 'forms');
if (!empty($allowed_forms)) {
$forms = array_map('intval', explode(',', $allowed_forms));
if (!in_array((int)$form_id, $forms, true)) {
return false;
}
}
// Case sensitivity check
if (formipay_get_post_meta($coupon_id, 'case_sensitive') === 'on') {
$stored_code = get_the_title($coupon_id);
if ($code !== $stored_code) {
return false;
}
}
// Check usage limits using meta counters
$use_limit = (int)formipay_get_post_meta($coupon_id, 'use_limit');
if ($use_limit > 0) {
$usage_count = (int)formipay_get_post_meta($coupon_id, 'usage_count');
if ($usage_count >= $use_limit) {
return false;
}
}
// Date validation with proper timezone handling
$date_limit = formipay_get_post_meta($coupon_id, 'date_limit');
if (!empty($date_limit) && is_numeric($date_limit)) {
$current_time = current_time('timestamp', true);
if ($current_time > (int)$date_limit) {
return false;
}
}
return $coupon_id;
}
// Function to check if a string contains HTML tags like <img>, <svg>, or <i>
function formipay_contains_html($string) {
return preg_match('/<(img|svg|i)(\s|>)/i', $string);
}
function formipay_generate_password() {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!!!';
$charactersLength = strlen($characters);
$password = '';
for ($i = 0; $i < 8; $i++) :
$password .= $characters[wp_rand(0, $charactersLength - 1)];
endfor;
$set_password = $password;
return $set_password;
}
function formipay_customer_mandatory_data() {
$mandatory_data = ['name'];
$formipay_settings = get_option( 'formipay_settings' );
if(isset($formipay_settings['customer_mandatory_data'])) {
foreach($formipay_settings['customer_mandatory_data'] as $category => $config){
if($config['id'] == 'mandatory'){
foreach($config['options'] as $data){
$mandatory_data[] = $data['id'];
}
}
}
}
return $mandatory_data;
}
function formipay_phone_country_code_options() {
$codes = formipay_country_array();
$options = [];
foreach($codes as $code){
$country_code = $code['phone'];
$options[$country_code] = '(' . $country_code . ') ' . $code['name'];
}
return $options;
}
function formipay_sanitize_array(array $input) {
$sanitized = [];
foreach ($input as $key => $value) {
if (is_array($value)) {
// Recursively sanitize nested arrays
$sanitized[$key] = formipay_sanitize_array( $value);
} else {
// Sanitize scalar values (adjust sanitization as needed)
$sanitized[$key] = sanitize_text_field( wp_unslash($value));
}
}
return $sanitized;
}
function formipay_generate_privacy_policy() {
// Check if page already exists
$existing_page = get_page_by_path('privacy-policy', OBJECT, 'page');
if (!$existing_page) {
// Get site-specific information
$site_name = esc_html(get_bloginfo('name'));
$site_url = esc_url(home_url());
$admin_email = sanitize_email(get_bloginfo('admin_email'));
$current_year = formipay_date('Y');
// Build policy content
$content = file_get_contents(FORMIPAY_PATH . '/public/templates/privacy-policy.php');
// Create privacy policy page
$page_id = wp_insert_post([
'post_title' => __('Privacy Policy', 'formipay'),
'post_name' => 'privacy-policy',
'post_content' => $content,
'post_status' => 'draft', // Set to draft for admin review
'post_type' => 'page',
'post_author' => get_current_user_id(),
'meta_input' => [
'_formipay_generated_policy' => true,
'_formipay_policy_version' => '1.0'
]
]);
// Add admin notice
if ($page_id && !is_wp_error($page_id)) {
add_action('admin_notices', function() use ($page_id) {
$edit_url = admin_url("post.php?post={$page_id}&action=edit");
echo '<div class="notice notice-success">';
echo '<p>' . sprintf(
// translators: %s is the drafted page URL.
esc_html__('Privacy Policy draft created. <a href="%s">Review and publish</a>', 'formipay'),
esc_url($edit_url)
) . '</p>';
echo '</div>';
});
}
}
}
function formipay_thankyoupage_allowed_html() {
return [
'div' => [
'id' => true,
'class' => true,
'data-*' => true
],
'h1' => [
'id' => true,
'class' => true,
'style' => true
],
'h2' => [
'id' => true,
'class' => true,
'style' => true
],
'h3' => [
'id' => true,
'class' => true,
'style' => true
],
'h4' => [
'id' => true,
'class' => true,
'style' => true
],
'h5' => [
'id' => true,
'class' => true,
'style' => true
],
'h6' => [
'id' => true,
'class' => true,
'style' => true
],
'form' => [
'id' => true,
'class' => true,
'action' => true,
'method' => true,
'enctype' => true
],
'input' => [
'type' => true,
'name' => true,
'value' => true,
'class' => true,
'id' => true,
'accept' => true,
'style' => true,
'data-*' => true
],
'button' => [
'id' => true,
'class' => true,
'type' => true,
'data-*' => true
],
'img' => [
'src' => true,
'alt' => true,
'class' => true,
'id' => true
],
'p' => ['class' => true],
'b' => [],
'i' => ['class' => true],
'table' => ['id' => true, 'class' => true],
'tbody' => [],
'tr' => [],
'th' => [],
'td' => [],
'br' => []
];
}
// add_action('admin_notices', function() {
// global $current_screen;
// echo '<pre>';
// print_r($current_screen);
// echo '</pre>';
// });

View File

@@ -0,0 +1,49 @@
<div class="formipay-screen-menu">
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a plugin asset and not a WordPress attachment. ?>
<img src="<?php echo esc_html(FORMIPAY_URL . 'admin/assets/img/formipay-logo-circle-white_256.png'); ?>" alt="Formipay">
<div class="screen-title">
<h1><?php echo esc_html__( 'Access Items', 'formipay' ); ?></h1>
<a id="add-new-item"><?php echo esc_html__( '+ Add New Item', 'formipay' ); ?></a>
</div>
</div>
<div class="wrap">
<div class="table-toolbar">
<div class="post-status-wrapper">
<button id="formipay-delete-selected" style="display:none;">
Delete Selected
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M20 6a1 1 0 0 1 .117 1.993L20 8h-.081L19 19a3 3 0 0 1-2.824 2.995L16 22H8c-1.598 0-2.904-1.249-2.992-2.75l-.005-.167L4.08 8H4a1 1 0 0 1-.117-1.993L4 6zm-9.489 5.14a1 1 0 0 0-1.218 1.567L10.585 14l-1.292 1.293l-.083.094a1 1 0 0 0 1.497 1.32L12 15.415l1.293 1.292l.094.083a1 1 0 0 0 1.32-1.497L13.415 14l1.292-1.293l.083-.094a1 1 0 0 0-1.497-1.32L12 12.585l-1.293-1.292l-.094-.083zM14 2a2 2 0 0 1 2 2a1 1 0 0 1-1.993.117L14 4h-4l-.007.117A1 1 0 0 1 8 4a2 2 0 0 1 1.85-1.995L10 2z" />
</svg>
</button>
<input type="hidden" id="post_status" value="all">
<a data-value="all" data-active="true"><?php echo esc_html__( 'All', 'formipay' ); ?></a><span class="all-post-count"></span> |
<a data-value="publish"><?php echo esc_html__( 'Published', 'formipay' ); ?></a><span class="publish-post-count"></span> |
<a data-value="draft"><?php echo esc_html__( 'Draft', 'formipay' ); ?></a><span class="draft-post-count"></span>
</div>
<div class="filter-bar">
<a id="reset-filter">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="#277aff" d="m16.325 18.8l-2.2 2.2L12 18.875l2.2-2.2q-.1-.275-.15-.575t-.05-.6q0-1.45 1.025-2.475T17.5 12q.45 0 .875.113t.8.312L16.8 14.8l1.4 1.4l2.375-2.35q.2.375.313.788T21 15.5q0 1.45-1.025 2.475T17.5 19q-.325 0-.612-.05t-.563-.15m4.45-8.8H18.7q-.65-2.2-2.475-3.6T12 5Q9.075 5 7.037 7.038T5 12q0 1.8.813 3.3T8 17.75V15h2v6H4v-2h2.35Q4.8 17.75 3.9 15.938T3 12q0-1.875.713-3.512t1.924-2.85t2.85-1.925T12 3q3.225 0 5.663 1.988T20.775 10"/></svg>
Reset
</a>
<div class="products">
<select id="products" class="form-tool filter-products"></select>
</div>
<div class="orderby">
<select id="orderby" class="form-tool">
<option value="ID" selected><?php echo esc_html__( 'ID', 'formipay' ); ?></option>
<option value="title"><?php echo esc_html__( 'Title', 'formipay' ); ?></option>
</select>
</div>
<div class="sort">
<select id="sort_by" class="form-tool">
<option value="desc" selected>DESC</option>
<option value="asc">ASC</option>
</select>
</div>
<div class="search">
<input type="text" id="keyword" placeholder="Keyword" class="form-tool">
</div>
</div>
</div>
<div id="formipay-access-items"></div>
</div>

39
admin/page-coupons.php Normal file
View File

@@ -0,0 +1,39 @@
<div class="formipay-screen-menu">
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a plugin asset and not a WordPress attachment. ?>
<img src="<?php echo esc_html(FORMIPAY_URL . 'admin/assets/img/formipay-logo-circle-white_256.png'); ?>" alt="Formipay">
<div class="screen-title">
<h1><?php echo esc_html__( 'Coupons', 'formipay' ); ?></h1>
<a id="add-new-coupon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0m6 0h6m-3-3v6" />
</svg>
<?php echo esc_html__( 'New Coupon', 'formipay' ); ?>
</a>
</div>
</div>
<div class="wrap">
<div class="table-toolbar">
<div class="post-status-wrapper">
<button id="formipay-delete-selected" style="display:none;">
Delete Selected
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M20 6a1 1 0 0 1 .117 1.993L20 8h-.081L19 19a3 3 0 0 1-2.824 2.995L16 22H8c-1.598 0-2.904-1.249-2.992-2.75l-.005-.167L4.08 8H4a1 1 0 0 1-.117-1.993L4 6zm-9.489 5.14a1 1 0 0 0-1.218 1.567L10.585 14l-1.292 1.293l-.083.094a1 1 0 0 0 1.497 1.32L12 15.415l1.293 1.292l.094.083a1 1 0 0 0 1.32-1.497L13.415 14l1.292-1.293l.083-.094a1 1 0 0 0-1.497-1.32L12 12.585l-1.293-1.292l-.094-.083zM14 2a2 2 0 0 1 2 2a1 1 0 0 1-1.993.117L14 4h-4l-.007.117A1 1 0 0 1 8 4a2 2 0 0 1 1.85-1.995L10 2z" />
</svg>
</button>
<input type="hidden" id="post_status" value="all">
<a data-value="all" data-active="true"><?php echo esc_html__( 'All', 'formipay' ); ?></a><span class="all-post-count"></span> |
<a data-value="active"><?php echo esc_html__( 'Active', 'formipay' ); ?></a><span class="active-post-count"></span> |
<a data-value="inactive"><?php echo esc_html__( 'Inactive', 'formipay' ); ?></a><span class="inactive-post-count"></span>
</div>
<div class="filter-bar">
<div class="products">
<select id="products" class="filter-products"></select>
</div>
<div class="search">
<input type="text" id="keyword" placeholder="Keyword" class="form-tool">
</div>
</div>
</div>
<div id="formipay-coupons"></div>
</div>

View File

@@ -0,0 +1 @@
<h1><?php echo esc_html__('Customer Details', 'formipay'); ?></h1>

30
admin/page-customers.php Normal file
View File

@@ -0,0 +1,30 @@
<div class="formipay-screen-menu">
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a plugin asset and not a WordPress attachment. ?>
<img src="<?php echo esc_html( FORMIPAY_URL . 'admin/assets/img/formipay-logo-circle-white_256.png' ); ?>" alt="Formipay">
<div class="screen-title">
<h1><?php echo esc_html__( 'Customers', 'formipay' ); ?></h1>
</div>
</div>
<div class="wrap">
<div class="table-toolbar">
<div class="filter-bar">
<a id="reset-filter">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="#277aff" d="m16.325 18.8l-2.2 2.2L12 18.875l2.2-2.2q-.1-.275-.15-.575t-.05-.6q0-1.45 1.025-2.475T17.5 12q.45 0 .875.113t.8.312L16.8 14.8l1.4 1.4l2.375-2.35q.2.375.313.788T21 15.5q0 1.45-1.025 2.475T17.5 19q-.325 0-.612-.05t-.563-.15m4.45-8.8H18.7q-.65-2.2-2.475-3.6T12 5Q9.075 5 7.037 7.038T5 12q0 1.8.813 3.3T8 17.75V15h2v6H4v-2h2.35Q4.8 17.75 3.9 15.938T3 12q0-1.875.713-3.512t1.924-2.85t2.85-1.925T12 3q3.225 0 5.663 1.988T20.775 10"/></svg>
Reset
</a>
<div class="limit">
<select id="limit" class="form-tool">
<option value="5">5</option>
<option value="10" selected>10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</div>
<div class="keyword">
<input id="keyword" class="form-tool" placeholder="<?php echo esc_html__( 'Keyword', 'formipay' ); ?>">
</div>
</div>
</div>
<div id="formipay-customers"></div>
</div>

54
admin/page-forms.php Normal file
View File

@@ -0,0 +1,54 @@
<div class="formipay-screen-menu">
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a plugin asset and not a WordPress attachment. ?>
<img src="<?php echo esc_html(FORMIPAY_URL . 'admin/assets/img/formipay-logo-circle-white_256.png'); ?>" alt="Formipay" />
<div class="screen-title">
<h1><?php echo esc_html__( 'Forms', 'formipay' ); ?></h1>
<a id="add-new-form">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0m6 0h6m-3-3v6" />
</svg>
<?php echo esc_html__( 'New Form', 'formipay' ); ?>
</a>
<button id="formipay-delete-selected" style="display:none;">
Delete Selected
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M20 6a1 1 0 0 1 .117 1.993L20 8h-.081L19 19a3 3 0 0 1-2.824 2.995L16 22H8c-1.598 0-2.904-1.249-2.992-2.75l-.005-.167L4.08 8H4a1 1 0 0 1-.117-1.993L4 6zm-9.489 5.14a1 1 0 0 0-1.218 1.567L10.585 14l-1.292 1.293l-.083.094a1 1 0 0 0 1.497 1.32L12 15.415l1.293 1.292l.094.083a1 1 0 0 0 1.32-1.497L13.415 14l1.292-1.293l.083-.094a1 1 0 0 0-1.497-1.32L12 12.585l-1.293-1.292l-.094-.083zM14 2a2 2 0 0 1 2 2a1 1 0 0 1-1.993.117L14 4h-4l-.007.117A1 1 0 0 1 8 4a2 2 0 0 1 1.85-1.995L10 2z" />
</svg>
</button>
</div>
</div>
<div class="wrap">
<div class="content-container">
<div class="table-toolbar">
<div class="post-status-wrapper">
<input type="hidden" id="post_status" value="all">
<a data-value="all" data-active="true"><?php echo esc_html__( 'All', 'formipay' ); ?></a><span class="all-post-count"></span> |
<a data-value="publish"><?php echo esc_html__( 'Published', 'formipay' ); ?></a><span class="publish-post-count"></span> |
<a data-value="draft"><?php echo esc_html__( 'Draft', 'formipay' ); ?></a><span class="draft-post-count"></span>
</div>
<div class="filter-bar">
<a id="reset-filter">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="#277aff" d="m16.325 18.8l-2.2 2.2L12 18.875l2.2-2.2q-.1-.275-.15-.575t-.05-.6q0-1.45 1.025-2.475T17.5 12q.45 0 .875.113t.8.312L16.8 14.8l1.4 1.4l2.375-2.35q.2.375.313.788T21 15.5q0 1.45-1.025 2.475T17.5 19q-.325 0-.612-.05t-.563-.15m4.45-8.8H18.7q-.65-2.2-2.475-3.6T12 5Q9.075 5 7.037 7.038T5 12q0 1.8.813 3.3T8 17.75V15h2v6H4v-2h2.35Q4.8 17.75 3.9 15.938T3 12q0-1.875.713-3.512t1.924-2.85t2.85-1.925T12 3q3.225 0 5.663 1.988T20.775 10"/></svg>
Reset
</a>
<div class="orderby">
<select id="orderby" class="form-tool">
<option value="ID" selected><?php echo esc_html__( 'ID', 'formipay' ); ?></option>
<option value="title"><?php echo esc_html__( 'Title', 'formipay' ); ?></option>
<option value="modified"><?php echo esc_html__( 'Modified Date', 'formipay' ); ?></option>
</select>
</div>
<div class="sort">
<select id="sort_by" class="form-tool">
<option value="desc" selected>DESC</option>
<option value="asc">ASC</option>
</select>
</div>
<div class="search">
<input type="text" id="keyword" placeholder="Keyword" class="form-tool">
</div>
</div>
</div>
<div id="formipay-forms"></div>
</div>
</div>

View File

@@ -0,0 +1,276 @@
<div class="formipay-screen-menu">
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a plugin asset and not a WordPress attachment. ?>
<img src="<?php echo esc_html( FORMIPAY_URL . 'admin/assets/img/formipay-logo-circle-white_256.png' ); ?>" alt="Formipay"> <!-- phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -->
<div class="screen-title">
<h1>
<?php echo
// translators: %d is the current order ID.
sprintf( esc_html__( 'Order %d', 'formipay'), intval(isset($_GET['order_id']) ? $_GET['order_id'] : 0) )
?>
</h1>
</div>
</div>
<div class="wrap">
<input type="hidden" id="order_id" value="<?php echo intval(isset($_GET['order_id']) ? $_GET['order_id'] : 0); ?>">
<div class="container-fluid">
<div class="row">
<div class="col-lg-7">
<div class="order-detail-card items-card">
<div class="card-title mt-3 mb-0"><?php echo esc_html__( 'Items', 'formipay' ); ?></div>
<div class="card mt-1 border-0 rounded-4 shadow-sm">
<div class="card-body p-0">
<table class="table placeholder-glow mb-0" id="order-items-table">
<tbody>
<tr>
<th><span class="placeholder col-6"></span></th>
<td><span class="placeholder col-4"></span></td>
</tr>
<tr>
<th><span class="placeholder col-6"></span></th>
<td><span class="placeholder col-4"></span></td>
</tr>
<tr>
<th><span class="placeholder col-6"></span></th>
<td><span class="placeholder col-4"></span></td>
</tr>
</tbody>
<tfoot>
<tr class="border-bottom-0">
<th class="border-bottom-0"><?php echo esc_html__( 'Total Order Value', 'formipay' ); ?></th>
<td id="order-total" class="border-bottom-0"><span class="placeholder col-4"></span></td>
</tr>
</tfoot>
</table>
</div>
<div class="card-footer bg-white d-flex justify-content-between align-items-center px-0" style="padding: .5rem!important;">
<?php echo esc_html__( 'Order Status', 'formipay' ); ?>
<select name="order_status" id="order_status" class="form-select rounded border border-secondary-subtle" data-order-id="<?php echo intval(isset($_GET['order_id']) ? $_GET['order_id'] : 0); ?>">
<?php
$order_statuses = formipay_order_status_list();
foreach($order_statuses as $key => $status) {
echo '<option value='. esc_html($key) .'>'. esc_html($status) .'</option>';
}
?>
</select>
</div>
</div>
</div>
<div class="order-detail-card form-data-card">
<div class="card-title mt-3 w-100 mb-0 d-flex justify-content-between align-items-center">
<?php echo esc_html__( 'Form Data', 'formipay' ); ?>
<button type="button" class="btn btn-secondary btn-sm edit-transaction-data rounded-4 px-3" data-loaded-button-text="<?php echo esc_html__( 'Edit Data', 'formipay' ); ?>" disabled>
<span class="spinner-border spinner-border-sm" aria-hidden="true"></span>
<span class="visually-hidden" role="status"></span>
</button>
<div class="update-transaction-buttons d-none">
<button type="button" class="btn btn-secondary btn-sm cancel-transaction-data rounded-4 px-3"><?php echo esc_html__( 'Cancel', 'formipay' ); ?></button>
<button type="button" class="btn btn-primary btn-sm update-transaction-data rounded-4 px-3"><?php echo esc_html__( 'Save Changes', 'formipay' ); ?></button>
</div>
</div>
<div class="card mt-1 border-0 rounded-4 shadow-sm">
<div class="card-body p-0 placeholder-glow">
<ul class="list-group list-group-flush" id="form-data-list">
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
</ul>
</div>
</div>
</div>
<div class="order-detail-card transaction-card">
<div class="card-title mt-3 mb-0">
<?php echo esc_html__( 'Transactions', 'formipay' ); ?>
</div>
<div class="card mt-1 border-0 rounded-4 shadow-sm">
<div class="card-body p-0">
<div class="rb-container">
<ul class="rb" id="transaction-list">
<li class="rb-item placeholder-glow">
<span class="placeholder col-3"></span>
<span class="placeholder col-10"></span>
</li>
<li class="rb-item placeholder-glow">
<span class="placeholder col-3"></span>
<span class="placeholder col-10"></span>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="order-detail-card notification-card">
<div class="card-title mt-3 mb-0"><?php echo esc_html__( 'Notification', 'formipay' ); ?></div>
<div class="card mt-1 border-0 rounded-4 shadow-sm">
<div class="card-body p-0 placeholder-glow">
<ul class="list-group list-group-flush" id="notification-list">
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="col-lg-5">
<div class="order-detail-card submission-detail-card">
<div class="card-title mt-3 mb-0"><?php echo esc_html__( 'Submission Details', 'formipay' ); ?></div>
<div class="card mt-1 border-0 rounded-4 shadow-sm">
<div class="card-body p-0 placeholder-glow">
<ul class="list-group list-group-flush" id="submission-detail-list">
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
</ul>
</div>
</div>
</div>
<div class="order-detail-card product-access-card">
<div class="card-title mt-3 w-100 mb-0 d-flex justify-content-between align-items-center">
<?php echo esc_html__( 'Product Access', 'formipay' ); ?>
<button type="button" class="btn btn-secondary btn-sm edit-access-data rounded-4 px-3" data-loaded-button-text="<?php echo esc_html__( 'Edit Data', 'formipay' ); ?>" disabled>
<span class="spinner-border spinner-border-sm" aria-hidden="true"></span>
<span class="visually-hidden" role="status"></span>
</button>
<div class="update-access-buttons d-none">
<button type="button" class="btn btn-secondary btn-sm cancel-access-data rounded-4 px-3"><?php echo esc_html__( 'Cancel', 'formipay' ); ?></button>
<button type="button" class="btn btn-primary btn-sm update-access-data rounded-4 px-3"><?php echo esc_html__( 'Save Changes', 'formipay' ); ?></button>
</div>
</div>
<div class="card mt-1 border-0 rounded-4 shadow-sm">
<form class="card-body p-0 placeholder-glow">
<ul class="list-group list-group-flush" id="access-detail-list">
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
<li class="list-group-item">
<b><span class="placeholder col-3"></span></b>
<p class="mb-0"><span class="placeholder col-8"></span></p>
</li>
</ul>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal" id="image-ligthbox">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body p-0">
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a placeholder for image lightbox. ?>
<img src="" style="width: 100%;">
</div>
</div>
</div>
</div>
<script id="order-item-row-template" type="text/x-handlebars-template">
{{#each items}}
<tr>
<th class="item-name fw-normal">{{item}}{{#if qty}}<br><span class="d-flex align-items-center gap-1"><span style="font-size: 10px;">✕</span>{{qty}}{{/if}}</span></th>
<td class="item-subtotal">{{subtotal_formatted}}</td>
</tr>
{{/each}}
</script>
<script id="form-data-item-template" type="text/x-handlebars-template">
{{#each datas as |data|}}
<li class="list-group-item px-0">
<b class="field-name">{{data.label}}</b>
<p class="field-value mt-1 mb-0" data-field-name="{{data.name}}">
{{data.value}}
</p>
</li>
{{/each}}
</script>
<script id="notification-data-template" type="text/x-handlebars-template">
{{#each datas as |row|}}
<li class="list-group-item d-flex justify-content-between align-items-center px-0 py-3">
<div class="notification-title">
<p class="mb-0"><b class="notification-title">{{row.title}}</b> <?php echo esc_html__('to', 'formipay'); ?> <span class="recipient-type">{{row.recipient_type}}</span> <?php echo esc_html__('at', 'formipay'); ?> <b class="notification-date">{{row.meta_data.request_date}}</b></p>
<span class="recipient badge text-bg-secondary rounded-pill me-1">
{{#ifEquals row.media "email"}}
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24">
<g fill="#fff">
<path d="M22 7.535V17a3 3 0 0 1-2.824 2.995L19 20H5a3 3 0 0 1-2.995-2.824L2 17V7.535l9.445 6.297l.116.066a1 1 0 0 0 .878 0l.116-.066z" />
<path d="M19 4c1.08 0 2.027.57 2.555 1.427L12 11.797l-9.555-6.37a3 3 0 0 1 2.354-1.42L5 4z" />
</g>
</svg>
{{/ifEquals}}
{{#ifEquals row.media "whatsapp"}}
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24">
<path fill="#fff" d="M18.497 4.409a10 10 0 0 1-10.36 16.828l-.223-.098l-4.759.849l-.11.011a1 1 0 0 1-.11 0l-.102-.013l-.108-.024l-.105-.037l-.099-.047l-.093-.058l-.014-.011l-.012-.007l-.086-.073l-.077-.08l-.067-.088l-.056-.094l-.034-.07l-.04-.108l-.028-.128l-.012-.102a1 1 0 0 1 0-.125l.012-.1l.024-.11l.045-.122l1.433-3.304l-.009-.014A10 10 0 0 1 5.056 4.83l.215-.203a10 10 0 0 1 13.226-.217M9.5 7.5A1.5 1.5 0 0 0 8 9v1a6 6 0 0 0 6 6h1a1.5 1.5 0 0 0 0-3h-1l-.144.007a1.5 1.5 0 0 0-1.128.697l-.042.074l-.022-.007a4.01 4.01 0 0 1-2.435-2.435l-.008-.023l.075-.041A1.5 1.5 0 0 0 11 10V9a1.5 1.5 0 0 0-1.5-1.5" />
</svg>
{{/ifEquals}}
<span class="recipient-text">{{row.recipient}}<span>
</span>
</div>
<span class="badge text-bg-primary rounded-pill notification-status">{{row.status}}</span>
</li>
{{/each}}
</script>
<script id="transaction-timeline-item" type="text/x-handlebars-template">
{{#each datas as |row|}}
<li class="rb-item" ng-repeat="itembx">
<div class="timestamp">
{{row.time}}
</div>
<div class="item-title">{{row.activity}}</div>
{{#ifEquals row.attachment "none"}}
{{else}}
<div class="item-thumbnail">
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a placeholder to show payment receipt. ?>
<img src="{{row.attachment}}" alt="payment-receipt" width="250" class="timeline-item-image border border-2 border-secondary shadow-sm rounded-3">
</div>
{{/ifEquals}}
</li>
{{/each}}
</script>
<script id="thankyou-access-template" type="text/x-handlebars-template">
<li class="list-group-item px-0 access-link">
<b><?php echo esc_html__('Access Link', 'formipay'); ?></b>
<div class="input-group mb-0 access-link-wrapper">
<input type="text" class="form-control rounded-start border border-secondary-subtle" placeholder="Recipient's username" aria-label="Recipient's username" aria-describedby="copy-link-access" value="{{data.link}}" readonly>
<button class="btn btn-outline-secondary rounded-end border border-secondary-subtle formipay-copy-button" type="button" id="copy-link-access" data-copy-value="{{data.link}}" data-copied-text="<?php echo esc_html__( 'Copied', 'formipay' ); ?>" data-copy-text="<?php echo esc_html__( 'Copy', 'formipay' ); ?>" data-not-copied-text="<?php echo esc_html__( 'Failed', 'formipay' ); ?>"><i class="bi bi-copy"></i> <?php echo esc_html__( 'Copy', 'formipay' ); ?></button>
</div>
</li>
<li class="list-group-item px-0 access-method" data-access-method="{{data.pass_method}}">
<b><?php echo esc_html__('Access Method', 'formipay'); ?></b>
<p class="mb-0">{{data.pass_method_label}}</p>
</li>
<li class="list-group-item px-0 access-password d-none" data-access-password="{{data.pass_word}}">
<b><?php echo esc_html__('Access Password', 'formipay'); ?></b>
<p class="mb-0">******</p>
</li>
</script>

42
admin/page-orders.php Normal file
View File

@@ -0,0 +1,42 @@
<div class="formipay-screen-menu">
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a plugin asset and not a WordPress attachment. ?>
<img src="<?php echo esc_html(FORMIPAY_URL . 'admin/assets/img/formipay-logo-circle-white_256.png'); ?>" alt="Formipay">
<div class="screen-title">
<h1><?php echo esc_html__( 'Orders', 'formipay' ); ?></h1>
</div>
</div>
<div class="wrap">
<div class="table-toolbar">
<div class="post-status-wrapper">
<input type="hidden" id="post_status" value="all">
<a data-value="all" data-active="true"><?php echo esc_html__( 'All', 'formipay' ); ?></a><span class="all-post-count"></span> |
<a data-value="completed"><?php echo esc_html__( 'Completed', 'formipay' ); ?></a><span class="completed-post-count"></span> |
<a data-value="on-hold"><?php echo esc_html__( 'On-Hold', 'formipay' ); ?></a><span class="on-hold-post-count"></span>
</div>
<div class="filter-bar">
<a id="reset-filter">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="#277aff" d="m16.325 18.8l-2.2 2.2L12 18.875l2.2-2.2q-.1-.275-.15-.575t-.05-.6q0-1.45 1.025-2.475T17.5 12q.45 0 .875.113t.8.312L16.8 14.8l1.4 1.4l2.375-2.35q.2.375.313.788T21 15.5q0 1.45-1.025 2.475T17.5 19q-.325 0-.612-.05t-.563-.15m4.45-8.8H18.7q-.65-2.2-2.475-3.6T12 5Q9.075 5 7.037 7.038T5 12q0 1.8.813 3.3T8 17.75V15h2v6H4v-2h2.35Q4.8 17.75 3.9 15.938T3 12q0-1.875.713-3.512t1.924-2.85t2.85-1.925T12 3q3.225 0 5.663 1.988T20.775 10"/></svg>
Reset
</a>
<div class="product">
<select id="products" class="form-tool"></select>
</div>
<div class="currency">
<select id="currencies" class="form-tool"></select>
</div>
<div class="limit">
<select id="limit" class="form-tool">
<option value="5">5</option>
<option value="10" selected>10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</div>
<div class="order_id">
<input id="order_id" class="form-tool" placeholder="Order ID">
</div>
</div>
</div>
<div id="formipay-orders"></div>
</div>

81
admin/page-products.php Normal file
View File

@@ -0,0 +1,81 @@
<div class="formipay-screen-menu">
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a plugin asset and not a WordPress attachment. ?>
<img src="<?php echo esc_html(FORMIPAY_URL . 'admin/assets/img/formipay-logo-circle-white_256.png'); ?>" alt="Formipay">
<div class="screen-title">
<h1><?php echo esc_html__( 'Products', 'formipay' ); ?></h1>
<a id="add-new-product">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0m6 0h6m-3-3v6" />
</svg>
<?php echo esc_html__( 'New Product', 'formipay' ); ?>
</a>
<a id="form-category" href="<?php echo esc_html(admin_url('edit-tags.php?taxonomy=formipay-form-category&post_type=formipay-form')); ?>">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M10 3H4a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1m10 0h-6a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1M10 13H4a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1m7 0a4 4 0 1 1-3.995 4.2L13 17l.005-.2A4 4 0 0 1 17 13" />
</svg>
<?php echo esc_html__( 'Categories', 'formipay' ); ?>
</a>
<button id="formipay-delete-selected" style="display:none;">
Delete Selected
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M20 6a1 1 0 0 1 .117 1.993L20 8h-.081L19 19a3 3 0 0 1-2.824 2.995L16 22H8c-1.598 0-2.904-1.249-2.992-2.75l-.005-.167L4.08 8H4a1 1 0 0 1-.117-1.993L4 6zm-9.489 5.14a1 1 0 0 0-1.218 1.567L10.585 14l-1.292 1.293l-.083.094a1 1 0 0 0 1.497 1.32L12 15.415l1.293 1.292l.094.083a1 1 0 0 0 1.32-1.497L13.415 14l1.292-1.293l.083-.094a1 1 0 0 0-1.497-1.32L12 12.585l-1.293-1.292l-.094-.083zM14 2a2 2 0 0 1 2 2a1 1 0 0 1-1.993.117L14 4h-4l-.007.117A1 1 0 0 1 8 4a2 2 0 0 1 1.85-1.995L10 2z" />
</svg>
</button>
</div>
</div>
<div class="wrap">
<div class="table-toolbar">
<div class="post-status-wrapper">
<input type="hidden" id="post_status" value="all">
<a data-value="all" data-active="true"><?php echo esc_html__( 'All', 'formipay' ); ?></a><span class="all-post-count"></span> |
<a data-value="publish"><?php echo esc_html__( 'Published', 'formipay' ); ?></a><span class="publish-post-count"></span> |
<a data-value="draft"><?php echo esc_html__( 'Draft', 'formipay' ); ?></a><span class="draft-post-count"></span>
</div>
<div class="filter-bar">
<a id="reset-filter">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path fill="#277aff" d="m16.325 18.8l-2.2 2.2L12 18.875l2.2-2.2q-.1-.275-.15-.575t-.05-.6q0-1.45 1.025-2.475T17.5 12q.45 0 .875.113t.8.312L16.8 14.8l1.4 1.4l2.375-2.35q.2.375.313.788T21 15.5q0 1.45-1.025 2.475T17.5 19q-.325 0-.612-.05t-.563-.15m4.45-8.8H18.7q-.65-2.2-2.475-3.6T12 5Q9.075 5 7.037 7.038T5 12q0 1.8.813 3.3T8 17.75V15h2v6H4v-2h2.35Q4.8 17.75 3.9 15.938T3 12q0-1.875.713-3.512t1.924-2.85t2.85-1.925T12 3q3.225 0 5.663 1.988T20.775 10"/></svg>
Reset
</a>
<div class="currency">
<select id="currencies" class="form-tool"></select>
</div>
<div class="category">
<select id="categories" class="form-tool">
<option value=""><?php echo esc_html__( 'All Categories', 'formipay' ); ?></option>
<?php
$taxonomy = 'formipay-product-category'; // Replace with your actual taxonomy
$terms = get_terms(array(
'taxonomy' => $taxonomy,
'hide_empty' => false, // Set to true to hide empty categories
));
if (!empty($terms) && !is_wp_error($terms)) {
foreach ($terms as $term) {
echo '<option value="' . intval($term->term_id) . '">' . esc_html($term->name) . '</option>';
}
}
?>
</select>
</div>
<div class="orderby">
<select id="orderby" class="form-tool">
<option value="ID" selected><?php echo esc_html__( 'ID', 'formipay' ); ?></option>
<option value="title"><?php echo esc_html__( 'Title', 'formipay' ); ?></option>
<option value="modified"><?php echo esc_html__( 'Modified Date', 'formipay' ); ?></option>
<option value="price"><?php echo esc_html__( 'Price Amount', 'formipay' ); ?></option>
</select>
</div>
<div class="sort">
<select id="sort_by" class="form-tool">
<option value="desc" selected>DESC</option>
<option value="asc">ASC</option>
</select>
</div>
<div class="search">
<input type="text" id="keyword" placeholder="Keyword" class="form-tool">
</div>
</div>
</div>
<div id="formipay-products"></div>
</div>

View File

@@ -0,0 +1,31 @@
<?php
/**
* File ini dipanggil oleh fungsi admin WordPress Anda untuk merender canvas.
*/
// 1. Ambil data awal dari WordPress
$post_id = isset($_GET['post']) ? intval($_GET['post']) : 0;
$saved_config_json = '[]';
if ($post_id > 0) {
$formipay_post_meta = get_post_meta($post_id, 'formipay_settings', true);
if (!empty($formipay_post_meta['fields'])) {
$saved_config_json = json_encode($formipay_post_meta['fields']);
}
}
// Data yang akan kita lewatkan ke Vue
// Menggantikan objek `formipay_admin` dari kode lama
$vue_app_data = [
'savedFields' => json_decode($saved_config_json), // Kirim sebagai objek, bukan string
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('formipay-secure-nonce'),
'formId' => $post_id,
'presets' => [
'countryList' => your_function_to_get_countries() // Panggil fungsi PHP Anda di sini
],
];
?>
<div id="formipay-builder-app" data-app-data='<?php echo esc_attr(json_encode($vue_app_data)); ?>'>
<p>Loading Form Builder...</p>
</div>

View File

@@ -0,0 +1,230 @@
<?php
$saved_config = [];
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if(isset($_GET['post']) && isset($_GET['action']) && $_GET['action'] == 'edit'){
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$formipay_post_meta = get_post_meta(intval(wp_unslash($_GET['post'])), 'formipay_settings', true);
$saved_config = $formipay_post_meta['fields'];
}
?>
<div class="d-flex mx-0 w-100">
<div class="p-3" id="sidebar_panel">
<input type="hidden" name="formipay_builder_canvas" value="<?php echo esc_attr( wp_create_nonce('formipay-form-builder-canvas') ) ?>">
<div id="add_field_form"></div>
</div>
<div class="position-relative p-2" id="fields_panel">
<div class="position-absolute fw-bold"><?php echo esc_html__('Preview', 'formipay'); ?></div>
<div id="preview-wrapper" class="h-100 d-flex flex-column gap-2"></div>
</div>
</div>
<!-- Config template -->
<script id="add-field-form-template" type="text/x-handlebars-template">
{{#each fields}}
<div class="field mb-2{{custom_class custom_class}}{{conditional_class conditional}}"{{{display conditional}}}>
<label for="{{id}}" class="form-label mb-0 small text-white {{#ifIn type "checkbox radio"}}d-none{{/ifIn}}">{{label}}</label>
{{#ifIn type "text number"}}
<input type="{{type}}" name="{{id}}" id="{{id}}" class="form-control formipay-builder-field" value="{{default}}" />
{{/ifIn}}
{{#ifEquals type "select"}}
<select name="{{id}}" class="form-select w-100 formipay-builder-field">
<option value="">-- Choose Type</option>
{{#each options}}
<option value="{{@key}}" {{selectedTheFirstOption @index}}>{{this}}</option>
{{/each}}
</select>
{{/ifEquals}}
{{#ifIn type "checkbox radio"}}
<input type="checkbox" name="{{id}}" id="{{id}}" class="form-control formipay-builder-field" value="no" />
<label for="{{id}}" class="form-label mb-0 small text-white">{{label}}</label>
{{/ifIn}}
{{#ifEquals type "textarea"}}
<textarea name="{{id}}" id="{{id}}" class="form-control formipay-builder-field">{{default}}</textarea>
<p class="mb-0 option-description small text-light">{{description}}</p>
{{/ifEquals}}
{{#ifEquals type "repeater"}}
<label class="form-label mb-0 small text-white">{{label}}</label>
<div class="d-flex flex-wrap gap-2 justify-content-start align-items-center">
{{#each fields}}
{{#ifEquals toggle "yes"}}
<div class="label-field">
<input type="checkbox" class="form-control option-field-toggle" data-child-field="{{id}}" id="repeater-child-{{@index}}_{{id}}">
<label for="repeater-child-{{@index}}_{{id}}" class="form-label text-sm mb-0 text-white">Show {{label}}</label>
</div>
{{/ifEquals}}
{{/each}}
</div>
<div class="repeater-child-wrapper">
<div class="repeater-child-input d-flex justify-content-start align-items-start gap-2 my-2">
<span class="grab mt-2">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#fff" d="M9 20q-.825 0-1.412-.587T7 18t.588-1.412T9 16t1.413.588T11 18t-.587 1.413T9 20m6 0q-.825 0-1.412-.587T13 18t.588-1.412T15 16t1.413.588T17 18t-.587 1.413T15 20m-6-6q-.825 0-1.412-.587T7 12t.588-1.412T9 10t1.413.588T11 12t-.587 1.413T9 14m6 0q-.825 0-1.412-.587T13 12t.588-1.412T15 10t1.413.588T17 12t-.587 1.413T15 14M9 8q-.825 0-1.412-.587T7 6t.588-1.412T9 4t1.413.588T11 6t-.587 1.413T9 8m6 0q-.825 0-1.412-.587T13 6t.588-1.412T15 4t1.413.588T17 6t-.587 1.413T15 8" />
</svg>
</span>
<div class="child-fields-wrapper w-100">
<div class="child-field-title text-bg-dark py-2 px-3 d-flex justify-content-between align-items-center">
<div class="the_title">Option</div>
<div class="the_buttons">
<button class="btn btn-sm text-bg-light mb-0 add-option">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="18" viewBox="0 0 24 24">
<path fill="#000" d="M9 18q-.825 0-1.412-.587T7 16V4q0-.825.588-1.412T9 2h9q.825 0 1.413.588T20 4v12q0 .825-.587 1.413T18 18zm0-2h9V4H9zm-4 6q-.825 0-1.412-.587T3 20V6h2v14h11v2zm4-6V4z" />
</svg>
</button>
<button class="btn btn-sm text-bg-light mb-0 delete-option">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="m12 13.4l-4.9 4.9q-.275.275-.7.275t-.7-.275t-.275-.7t.275-.7l4.9-4.9l-4.9-4.9q-.275-.275-.275-.7t.275-.7t.7-.275t.7.275l4.9 4.9l4.9-4.9q.275-.275.7-.275t.7.275t.275.7t-.275.7L13.4 12l4.9 4.9q.275.275.275.7t-.275.7t-.7.275t-.7-.275z" />
</svg>
</i></button>
<button class="btn btn-sm text-bg-light mb-0 open-collapse open-option">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="m12 15l-5-5h10z" />
</svg>
</button>
</div>
</div>
<div class="child-field-wrapper p-2 bg-light text-dark" style="display:none;">
<div class="child-field-row row">
<div class="child-field-image col-6 child-field-col-1 child-field-thumbnail repeater-child-input-thumbnail" style="display: none;">
<div class="child-field-image-wrapper formipay-builder-field">
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a placeholder to display an image preview and will be managed by JS ?>
<img src="" class="d-none" style="width: 100%;" alt="Image Preview"/>
<i data-field="field-image" class="bi bi-file-earmark-image-fill pointer fs-3 text-secondary add-thumbnail child-field-image"{{{toggleDisplay toggle}}}></i>
<input type="hidden" class="field-image-id d-none">
<input type="hidden" class="field-image-url d-none">
<button data-field="field-image" class="btn btn-sm add-thumbnail bg-secondary text-white">Choose Image</button>
</div>
</div>
<div class="col child-field-col-2">
<table class="table child-field-input-table">
<tbody>
{{#each fields}}
{{#ifNotIn type "image toggle"}}
<tr class="child-field-{{id}} repeater-child-input-{{id}}"{{{toggleDisplay toggle}}}>
<th>{{label}}</th>
<td>
<input type="{{type}}" class="form-control formipay-builder-field formipay-builder-option-field" value="{{default}}" placeholder="{{label}}" />
</td>
</tr>
{{/ifNotIn}}
{{#ifEquals type "toggle"}}
<tr class="child-field-{{id}}"{{{toggleDisplay toggle}}}>
<th>{{label}}</th>
<td>
<div class="form-check form-switch align-items-baseline mt-2 mb-0 formipay-builder-field formipay-builder-option-field">
<input class="form-check-input check-qty repeater-child-input-qty" type="checkbox" role="switch">
<label class="form-check-label text-white text-nowrap"><span class="small">✕</span> Quantity</label>
</div>
</td>
</tr>
{{/ifEquals}}
{{/each}}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{{/ifEquals}}
</div>
{{/each}}
<button type="button" class="btn btn-light add-field w-100">Add Field</button>
</script>
<!-- Preview template -->
<script id="preview-template" type="text/x-handlebars-template">
{{#each fields}}
{{!-- Hidden field --}}
<div class="preview-field d-flex gap-2 align-items-center" data-field="{{field_id}}" data-field-type="{{field_type}}" {{#ifEquals field_type "hidden"}}style="opacity: .5;"{{/ifEquals}}>
<span class="grab pb-4">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#000" d="M9 20q-.825 0-1.412-.587T7 18t.588-1.412T9 16t1.413.588T11 18t-.587 1.413T9 20m6 0q-.825 0-1.412-.587T13 18t.588-1.412T15 16t1.413.588T17 18t-.587 1.413T15 20m-6-6q-.825 0-1.412-.587T7 12t.588-1.412T9 10t1.413.588T11 12t-.587 1.413T9 14m6 0q-.825 0-1.412-.587T13 12t.588-1.412T15 10t1.413.588T17 12t-.587 1.413T15 14M9 8q-.825 0-1.412-.587T7 6t.588-1.412T9 4t1.413.588T11 6t-.587 1.413T9 8m6 0q-.825 0-1.412-.587T13 6t.588-1.412T15 4t1.413.588T17 6t-.587 1.413T15 8" />
</svg>
</span>
<div class="formipay-field w-100">
<div class="d-flex justify-content-between field-controls">
<label for="{{field_id}}" class="{{labelClass field_type}}">{{label}}{{#ifEquals is_required "yes"}} <span style="color: red;">(*)</span>{{/ifEquals}}</label>
<div class="field-icons d-flex gap-2 align-items-center the_buttons">
<button class="btn btn-sm edit-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M5 19h1.425L16.2 9.225L14.775 7.8L5 17.575zm-2 2v-4.25L16.2 3.575q.3-.275.663-.425t.762-.15t.775.15t.65.45L20.425 5q.3.275.438.65T21 6.4q0 .4-.137.763t-.438.662L7.25 21zM19 6.4L17.6 5zm-3.525 2.125l-.7-.725L16.2 9.225z" />
</svg>
</button>
<button class="btn btn-sm delete-preview-field">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24">
<path fill="#000" d="M7 21q-.825 0-1.412-.587T5 19V6H4V4h5V3h6v1h5v2h-1v13q0 .825-.587 1.413T17 21zm2-4h2V8H9zm4 0h2V8h-2z" />
</svg>
</button>
</div>
</div>
<input type="hidden" name="{{@key}}" class="formipay-field-setup" value='{{json this}}' />
{{!-- Input fields --}}
{{#ifNotEquals field_type "textarea"}}
{{#ifIn field_type "divider page_break select checkbox radio country_list"}}
{{#ifEquals field_type "divider"}}
<span class="divider-line"></span>
{{/ifEquals}}
{{#ifEquals field_type "page_break"}}
<span class="divider-line"></span>
{{/ifEquals}}
{{#ifEquals field_type "select"}}
<select id="{{field_id}}" class="formipay-input formipay-form-field w-100">
{{#if placeholder}}
<option>{{placeholder}}</option>
{{/if}}
{{#each field_options}}
<option value="{{this.value}}" data-calc-value="{{this.amount}}">{{this.label}}</option>
{{/each}}
</select>
{{/ifEquals}}
{{#ifEquals field_type "country_list"}}
<select id="{{field_id}}" class="formipay-input formipay-form-field w-100">
<option>-- {{placeholder}}</option>
{{{countryListOptions}}}
</select>
{{/ifEquals}}
{{#ifIn field_type "checkbox radio"}}
<div class="formipay-checkbox-wrapper" style="grid-template-columns: repeat({{layoutColumn layout}}, 1fr);">
{{#each field_options}}
<div class="formipay-checkbox-group">
{{#if image_url}}
<?php // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- This image is a placeholder to display an image preview and will be managed by JS ?>
<img src="{{this.image_url}}" alt="{{this.label}}" style="width: 100%; height: 150px; object-fit: contain;" />
{{/if}}
<input type="{{../field_type}}" id="{{../config_id}}-{{@index}}" name="{{name ../field_type ../field_id @index}}" class="formipay-input formipay-form-field" value="{{this.value}}" data-calc-value="{{this.amount}}"/>
<label for="{{../config_id}}-{{@index}}">{{this.label}}</label>
</div>
{{/each}}
</div>
{{/ifIn}}
{{else}}
<input type="{{field_type}}" id="{{field_id}}" class="formipay-input formipay-form-field w-100" placeholder="{{placeholder}}" value="{{default_value}}" {{#ifEquals field_type "number"}}data-calc-value="{{calc_value}}"{{/ifEquals}} />
{{/ifIn}}
{{else}}
{{!-- Textarea field --}}
<textarea id="{{field_id}}" rows="4" class="formipay-input formipay-form-field w-100" placeholder="{{placeholder}}">{{default_value}}</textarea>
{{/ifNotEquals}}
<p class="formipay-inline-desc">{{description}}</p>
</div>
{{#ifEquals field_type "page_break"}}
<span class="scissors">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path fill="#000" d="m12 14l-2.35 2.35q.2.375.275.8T10 18q0 1.65-1.175 2.825T6 22t-2.825-1.175T2 18t1.175-2.825T6 14q.425 0 .85.075t.8.275L10 12L7.65 9.65q-.375.2-.8.275T6 10q-1.65 0-2.825-1.175T2 6t1.175-2.825T6 2t2.825 1.175T10 6q0 .425-.075.85t-.275.8L20.6 18.6q.675.675.3 1.538T19.575 21q-.275 0-.537-.112t-.463-.313zm3-3l-2-2l5.575-5.575q.2-.2.463-.312T19.574 3q.95 0 1.313.875t-.313 1.55zM6 8q.825 0 1.413-.587T8 6t-.587-1.412T6 4t-1.412.588T4 6t.588 1.413T6 8m6 4.5q.2 0 .35-.15t.15-.35t-.15-.35t-.35-.15t-.35.15t-.15.35t.15.35t.35.15M6 20q.825 0 1.413-.587T8 18t-.587-1.412T6 16t-1.412.588T4 18t.588 1.413T6 20" />
</svg>
</span>
{{/ifEquals}}
</div>
{{/each}}
</script>

View File

@@ -0,0 +1,48 @@
<div class="global-paypal-instruction" style="display:none;">
<h5>Step 1: Create a PayPal Business Account</h5>
<ul class="paypal-instruction-point">
<li><b>Go to PayPal Website:</b> Open your web browser and go to PayPal\'s website.</li>
<li><b>Sign Up:</b> Click on <u>Sign Up</u> in the top right corner.</li>
<li><b>Select Business Account:</b> Choose the "Business Account" option and click <b>Continue</b>.</li>
<li><b>Fill in Your Information:</b> Enter your email address and create a password. Follow the steps to fill in your business information (name, address, etc.).</li>
<li><b>Complete Verification:</b> PayPal may ask you to verify your identity by confirming your email address and phone number. Follow the prompts in your email and on the website to complete this step.</li>
</ul>
<h5>Step 2: Access PayPal Developer Portal.</h5>
<ul class="paypal-instruction-point">
<li><b>Go to PayPal Developer Website:</b> Open a new browser tab and navigate to the <a href="https://developer.paypal.com/" target="_blank"><u>PayPal Developer site</u></a>.</li>
<li><b>Log In:</b> Click “Log In to Dashboard” in the top-right corner and use your PayPal business account credentials to log in.</li>
</ul>
<h5>Step 3: Create PayPal REST API App</h5>
<ul class="paypal-instruction-point">
<li><b>Navigate to Dashboard:</b> Once logged in, you will see the Developer Dashboard.</li>
<li><b>Click on <u>My Apps & Credentials</u></b>: Look for this option in the left sidebar.</li>
<li><span><b>Create an App:</b></span>
<ul>
<li>Find the “REST API apps” section.</li>
<li>Click the "Create App" button.</li>
</ul>
</li>
<li><b>Name Your App:</b> Give your app a name (e.g., “My WordPress Store”) and click “Create App”.</li>
<li><span><b>View Your Credentials:</b></span> Once created, you\'ll see your new app. Here you will find:
<ul>
<li>Client ID</li>
<li>Secret</li>
<li>Sandbox and Live credentials (make sure to toggle between Sandbox and Live as needed)</li>
</ul>
</li>
</ul>
<h5>Step 4: Gather Required Merchant Data</h5>
<p>Now that you have created your PayPal app, you can gather the required merchant data.</p>
<ul class="paypal-instruction-point">
<li><b>PayPal Client ID:</b> Copy the Client ID from your app settings.</li>
<li><b>PayPal Secret:</b> Copy the Secret from your app settings.</li>
<li><b>PayPal Environment:</b> Decide whether you want to work in Sandbox (for testing) or Live (for actual transactions). Make a note of which environment you are using.</li>
<li><b>Merchant Email:</b> Log in to your PayPal account and note the email address linked to your account. This is typically the email you used when signing up.</li>
</ul>
<h5>Final Notes</h5>
<ul>
<li>Keep your PayPal Client ID and Secret secure; do not share them publicly.</li>
<li>Always test your integration in the Sandbox environment before going Live.</li>
</ul>
</div>
<div id="connect-status"></div>

View File

@@ -0,0 +1,114 @@
<div id="product-variables-table" class="wpcfto_generic_field wpcfto_generic_field_html">
<div class="wpcfto-field-content">
<table class="wpcfto-table formipay-variations-table">
<thead>
<tr>
<th data-cell="toggle">{{ product_details.variation_table.th_toggle }}</th>
<th data-cell="name">{{ product_details.variation_table.th_name }}</th>
<th data-cell="stock">{{ product_details.variation_table.th_stock }}</th>
<th data-cell="weight" v-if="isPhysical">{{ product_details.variation_table.th_weight }}</th>
<template v-if="pricingMethod !== 'manual'">
<th data-cell="price">{{ product_details.variation_table.th_price }}</th>
<th data-cell="sale">{{ product_details.variation_table.th_sale }}</th>
</template>
<template v-else>
<th data-cell="prices">{{ product_details.variation_table.th_prices_overall }}</th>
</template>
<th class="toggle-column"></th>
</tr>
</thead>
<tbody v-if="tableRows.length > 0">
<template v-for="(row, idx) in tableRows">
<tr :key="row.key" :class="['wpcfto-repeater-single', { 'variation-inactive': !row.active }]">
<td data-cell="toggle" style="text-align:center;">
<label class="switch">
<input type="checkbox" v-model="row.active" />
<span class="slider"></span>
</label>
</td>
<td data-cell="name">
<input type="text" v-model="row.name" class="wpcfto-admin-input" readonly :disabled="!row.active" />
</td>
<td data-cell="stock">
<input type="number" v-model.number="row.stock" class="wpcfto-admin-input" min="0" :placeholder="'∞'" style="width:100%;text-align:right;" :disabled="!row.active" />
</td>
<td v-if="isPhysical" data-cell="weight">
<input type="number" v-model.number="row.weight" step="0.01" style="width:100%; text-align:right;" :disabled="!row.active" />
</td>
<template v-if="pricingMethod !== 'manual'">
<td data-cell="price">
<price-input :value="row.price" @input="row.price = $event" :currency-symbol="currencySymbol" :currency-decimal-digits="currencyDecimalDigits" :disabled="!row.active" />
</td>
<td data-cell="sale">
<price-input :value="row.sale" @input="row.sale = $event" :currency-symbol="currencySymbol" :currency-decimal-digits="currencyDecimalDigits" :disabled="!row.active" />
</td>
</template>
<template v-else>
<td data-cell="prices" class="manual-price-hint">
<span @click="row.expanded = !row.expanded">{{ product_details.variation_table.manual_price_hint }}</span>
</td>
</template>
<td class="toggle-column" style="text-align:center;">
<button v-if="pricingMethod === 'manual' && row.prices.length > 0" @click="row.expanded = !row.expanded" class="button-link child-row-toggle" :class="row.expanded ? 'active' : ''" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1">
<circle cx="12" cy="12" r="10" />
<path d="M15 12.915S12.79 15.5 12 15.5s-3-2.585-3-2.585M15 8.5s-2.21 2.585-3 2.585S9 8.5 9 8.5" />
</g>
</svg>
</button>
</td>
</tr>
<tr v-if="pricingMethod === 'manual' && row.expanded" :key="row.key + '-details'" class="variation-details-row">
<td :colspan="isPhysical ? 7 : 6">
<div class="variation-details-content">
<table class="wpcfto-table inner-table" v-if="row.prices.length > 0">
<thead>
<tr>
<th>{{ product_details.variation_table.child_th_currency }}</th>
<th>{{ product_details.variation_table.child_th_regular }}</th>
<th>{{ product_details.variation_table.child_th_sale }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(priceEntry, p_idx) in row.prices" :key="p_idx">
<td>{{ priceEntry.currency.split(':::')[1] }} ({{ priceEntry.currency.split(':::')[2] || priceEntry.currency.split(':::')[0] }})</td>
<td>
<price-input :value="priceEntry.regular_price" @input="priceEntry.regular_price = $event" :currency-symbol="priceEntry.currency.split(':::')[2] || priceEntry.currency.split(':::')[0]" :currency-decimal-digits="parseInt(priceEntry.currency_decimal_digits)" :disabled="!row.active" />
</td>
<td>
<price-input :value="priceEntry.sale_price" @input="priceEntry.sale_price = $event" :currency-symbol="priceEntry.currency.split(':::')[2] || priceEntry.currency.split(':::')[0]" :currency-decimal-digits="parseInt(priceEntry.currency_decimal_digits)" :disabled="!row.active" />
</td>
</tr>
</tbody>
</table>
<p v-else style="padding: 10px; text-align:center;">{{ product_details.variation_table.no_currencies }}</p>
</div>
</td>
</tr>
</template>
</tbody>
<tbody v-else>
<tr>
<td :colspan="isPhysical ? 7 : 6" style="text-align:center;color:#8c99a5;">
{{ product_details.variation_table.no_variations }}
</td>
</tr>
</tbody>
</table>
<input type="hidden" name="product_variables" v-model="jsonValue" />
</div>
</div>