I have this delete function :
showDeleteConfirmation(value, id, index, thisHandler) {
//const { extraitMP3 } = this.state;
confirm({
title: 'Voulez vous supprimer cette audio ?',
content: '',
okText: 'Oui, je confirme',
okType: 'danger',
cancelText: 'Non',
onOk() {
deleteMp3Request(id);
var { extraitMP3 } = thisHandler.state;
var array = [];
for (var key in extraitMP3) {
array.push(extraitMP3[key]);
}
// console.log('array',array)
const result = array.map(d => ({
...d,
TypeMp3List:
Object.fromEntries(
//console.log(Object.entries(d.TypeMp3List)),
Object.entries(d.TypeMp3List).splice(index,id)
)
}))
// console.log('result',result)
thisHandler.setState({ extraitMP3: result })
NotificationManager.success("le fichier audio est supprimé avec succès !", "");
},
onCancel() {
},
});
}
I want to replace the text messages with :
title: <IntlMessages id="message.required.titresuppressionmp3" />,
content: '',
okText: <IntlMessages id="message.required.confirmation" />,
okType: <IntlMessages id="message.required.danger" />,
cancelText: <IntlMessages id="message.required.non"/>,
I did the import but it's not working correctly What should I do exactly to be read successfully. Any help would be appreciated. Thank you
The browsers doesn't support JSX, so you must use babel to convert the JSX into understandable for the browser javascript code. Check this tutorial
Related
I have a problem with reseting fields of my form.
I have a form. The user can adding another forms and another ...
If everything is OK, I would like to recording data in my DB and in my store AND reset all of inputs of my form. This is this last point I cannot do.
I have tried different solutions but It does not work.
This is my code :
<div v-for="(question, index) in questionsSignaletiques" :key="index" class="blockQuestion" >
<!--form to add questions : one form per question, each form have a different name in the ref -->
<a-form-model
layout="inline"
:ref="'p' + index"
>
<p>New question</p>
<a-alert v-if="question.error.here" type="error" :message="question.error.message" show-icon />
<a-form-model-item>
<a-input v-model="question.question.type" placeholder="Title">
</a-input>
</a-form-model-item>
<a-form-model-item>
<a-input v-model="question.question.item" placeholder="Item">
</a-input>
</a-form-model-item>
<br><br>
<a-form-model-item label="Question multiple" prop="delivery">
<a-switch v-model="question.question.multiple" />
</a-form-model-item>
<a-form-model-item label="Obligatoire" prop="delivery">
<a-switch v-model="question.question.obligatoire" />
</a-form-model-item>
<br><br>
<div class="blockChoices">
<div v-for="subrow in question.question.choices">
<a-form-model-item>
<a-input v-model="subrow.name" placeholder="Choix">
</a-input>
</a-form-model-item>
</div>
</div>
<a-button #click="addChoice(question)" type="secondary">Add a choice</a-button>
</a-form-model>
</div>
<div>
<a-button #click="addItem" type="secondary">Add a question</a-button>
</div>
<br>
<div>
<a-button #click="submit" type="primary">Send</a-button>
</div>
Javascript code :
data() {
return {
idStudy: this.$route.params.id,
aucuneQuestion:false,
questionsSignaletiques: [
{
"study":"/api/studies/" + this.$route.params.id,
"question":
{
type: "",
item: "",
multiple: false,
obligatoire: false,
inverse: false,
barometre: false,
originale: false,
signaletik: true,
choices: [{name:''}]
},
"error": {
message:"",
here:false
}
}
],
}
},
mounted() {
//retreive all the questions still recorded
axios
.get('http://127.0.0.1:8000/api/studies/' + this.idStudy + '/question_studies?question.signaletik=true')
.then((result)=>{
console.log(result.data["hydra:member"])
this.aucuneQuestion = result.data["hydra:member"].length === 0;
//on met les données dans le store
this.$store.commit("setListeQuestionsSignaletiques", result.data["hydra:member"])
})
.catch(err=>console.log(err))
},
methods: {
//Adding a question
addItem () {
this.questionsSignaletiques.push(
{
"study":"/api/studies/" + this.idStudy,
"question":
{
type: "",
item: "",
multiple: false,
obligatoire: false,
inverse: false,
barometre: false,
originale: false,
signaletik: true,
choices: [{name:''}]
},
"error": {
message:"",
here:false
}
}
)
},
//adding a choice
addChoice: function(choice) {
choice.question.choices.push({
name: ''
})
},
// Sending the forms
submit () {
//loop table to retrieve all questions and indexes if the user adding several questions
this.questionsSignaletiques.forEach((element,index) =>
{
const inputType = element.question.type
const inputItem = element.question.item
const inputChoice = element.question.choices
//loop on choices to see if empty one or not
for (const oneChoice of inputChoice)
{
if ((inputChoice.length == 1) ||(inputChoice.length == 2 && oneChoice.name == ""))
{
element.error.here=true
element.error.message = "You must have two choices at least"
return false; // stop here if error
}
else
{}
}// end loop of choices
// verify other fields
if (inputType == "" || inputItem =="")
{
element.error.here=true
element.error.message = "Title and item must not be empty"
}
else
{
// everything is ok we can record in db and store
//reset fields == does not work
this.$refs['p' + index][0].fields.resetField()
//this.$refs['p' + index][0].resetFields();
// adding questions in db one by one
/*
axios
.post('http://127.0.0.1:8000/api/question_studies', element)
.then((result)=>{
console.log(result)
//add in the state
this.$store.commit("addQuestionSignaletique", element)
})
.catch(error => {
console.log("ERRRR:: ",error);
});
*/
}
}) //end loop foreach
}
}
};
Thanks a lot for help
EDIT AFTER THE FIRST ANSWER
Ok I didn't know. So I changed my mind : I added a "show" in my "data" which is true at the beginning. If everything is ok, I save the question and set the show to false.
The problem now is that when I have a question that is OK and the other one that is not. When I correct the question that was not ok and save it, BOTH questions go into the STATE. So there is a duplicate in my state AND my DB... What can I do? This is the code :
I just added this in the HTML :
<div v-for="(question, index) in questionsSignaletiques" :key="index" >
<a-form-model
layout="inline"
v-if="question.show"
class="blockQuestion"
>
...
data() {
return {
idStudy: this.$route.params.id,
aucuneQuestion:false,
questionsSignaletiques: [
{
"study":"/api/studies/" + this.$route.params.id,
"question":
{
type: "",
item: "",
multiple: false,
obligatoire: false,
inverse: false,
barometre: false,
originale: false,
signaletik: true,
choices: [{name:''}]
},
"error": {
message:"",
here:false
},
"show":true,
}
],
}
},
mounted() {
//retrieve question still recorded
axios
.get('http://127.0.0.1:8000/api/studies/' + this.idStudy + '/question_studies?question.signaletik=true')
.then((result)=>{
console.log(result.data["hydra:member"])
this.aucuneQuestion = result.data["hydra:member"].length === 0;
this.$store.commit("setListeQuestionsSignaletiques", result.data["hydra:member"])
})
.catch(err=>console.log(err))
},
methods: {
//adding a question
addItem () {
this.questionsSignaletiques.push(
{
"study":"/api/studies/" + this.idStudy,
"question":
{
type: "",
item: "",
multiple: false,
obligatoire: false,
inverse: false,
barometre: false,
originale: false,
signaletik: true,
choices: [{name:''}]
},
"error": {
message:"",
here:false
},
"show":true
}
)
},
//adding a choice
addChoice: function(choice) {
choice.question.choices.push({
name: ''
})
},
// submit the form
submit () {
this.questionsSignaletiques.forEach((element,index) =>
{
const inputType = element.question.type
const inputItem = element.question.item
const inputChoice = element.question.choices
for (const oneChoice of inputChoice)
{
if ((inputChoice.length == 1) ||(inputChoice.length == 2 && oneChoice.name == ""))
{
element.error.here=true
element.error.message = "You must have two choices at least"
return false; //on s'arrête là si il y a une erreur
}
else
{
console.log("no problem")
}
}
if (inputType == "" || inputItem =="")
{
element.error.here=true
element.error.message = "You must fill type and item"
}
else
{
// hide the question form
element.show =false
//adding in db
axios
.post('http://127.0.0.1:8000/api/question_studies', element)
.then((result)=>{
//add in the state
this.$store.commit("addQuestionSignaletique", element)
})
.catch(error => {
console.log("ERRRR:: ",error);
});
}
}) //end loop foreach
}
}
};
Thanks for help !
form.reset() does not work when using v-model.
Reset the reactive data instead.
reset() {
this.question.question.type = ""
...
...
}
For school I'm making a blog with some people and now I want to upload an image to the blog post. But then this uploading the post the error:
{message: "The given data was invalid.", errors: {image: ["The image field is required."]}}
errors: {image: ["The image field is required."]}
message: "The given data was invalid."
I have searched on the internet and looked at other conversations, but I can't find my solution.
Here are my codes:
This is the form in a VueJS component:
<form method="post" action="./api/post" #submit.prevent="createPost()" enctype="multipart/form-data">
<p>Titel van de post</p>
<input type="text" placeholder="Titel van de post" name="title" v-model="title">
<p>Beschrijving bij de post</p>
<textarea placeholder="Beschrijving bij de post" name="description" v-model="description"/>
<input type="file" id="image" name="image" ref="image" v-on:change="(e) => {this.onChangeFileUpload(e)}"/>
<div class="uploadtimer">
<p>Selecteer een tijd wanneer de post moet worden getoond. (Niet verplicht)</p>
<datetime format="YYYY-MM-DD H:i" v-model="uploadTime"></datetime>
</div>
<input type="submit" class="input-submit">
</form>
The script in the component:
<script>
import datetime from 'vuejs-datetimepicker';
export default {
components: { datetime },
data() {
return {
title: '',
description: '',
uploadTime: '',
image: '',
}
},
methods: {
onChangeFileUpload(e) {
this.image = e.target.files[0];
},
createPost() {
let data = new FormData;
data.append('image', this.image);
axios.post('./api/post', {
title: this.title,
description: this.description,
data,
uploadTime: this.uploadTime,
}).then(response => {
}).catch(response => {
document.getElementById('errorMSG').style.display = 'flex';
document.getElementById('errorMSG').innerHTML = '<span>!</span><p>Er is iets mis gegaan met het plaatsen van de post.</p>';
setTimeout(function() {
document.getElementById('errorMSG').style.display = 'none';
}, 5000);
});
}
},
}
And the Controller function I'm using:
public function store(Request $request)
{
if(Auth::check()) {
$this->validate($request, [
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg',
]);
$post = new Post();
$post->title = $request->input('title');
$post->description = $request->input('description');
$image = $request->file('image');
$imageExtension = $image->getClientOriginalExtension();
$imageName = time() . '_' . $imageExtension;
$image->move(public_path('/imgs/users-avatars/'), $imageName);
$post->image = '/imgs/posts-images/' . $imageName;
$post->uploadTime = $request->input('uploadTime');
$post->user_id = Auth::User()->id;
$post->save();
return (['message' => 'succes']);
} else {
return (['message' => 'error', 'handler' => 'Authenticated user is required!']);
}
}
How can I fix this?
You may use either image rule (that validates a file to be jpeg, png, bmp, gif, svg, or webp) or use mimes:jpeg,png,jpg,gif,svg:
So your validation would be either:
'image' => 'required|file|mimes:jpeg,png,jpg,gif,svg|max:2048',
Or:
'image' => 'required|file|image|max:2048',
Additionally, the file rule checks if the field is a successfully uploaded file and max:2048 rule checks if the file size is less than or equal to 2048 kilobytes (2MB). See Laravel docs for more info.
On VueJs, you have to append all your inputs to a FormData:
let data = new FormData;
data.append('image', this.image);
data.append('title', this.title);
data.append('description', this.description);
data.append('uploadTime', this.uploadTime);
axios.post('./api/post', data)
.then(
//...
I'm new to symfony, I render forms throughout a JSON so whenever I click on an icon it shows different forms (to change firstname, lastname...).
I return thoses forms as a JSON :
public function profileSettings()
{
$user = $this->getUser();
// Formulaire d'informations concernant le compte
$formAccountSettings = $this->createForm(AccountSettingsType::class, $user, [
'userEmail' => $user->getEmail(),
'userUsername' => $user->getUsername(),
]);
// Formulaire d'informations personnel
$formPersonnalSettings = $this->createForm(PersonnalSettingsType::class, $user, [
'userFirstname' => $user->getFirstname(),
'userLastname' => $user->getLastname(),
]);
// Retour en format JSON des 3 requêtes sous tableau
return $this->json(
[
'formAccountSettingsView' =>
$this->render('user/_accountSettings.html.twig', [
'form' => $formAccountSettings->createView(),
]),
'currentUser' => $user,
'formPersonnalSettingsView' => $this->render('user/_accountSettings.html.twig', [
'form' => $formPersonnalSettings->createView(),
]),
]
);
}
Here is how I display this :
$('#settings-user li').on('click', function (e) {
$.ajax({
type: 'GET',
url: "/website-skeleton/public/index.php/json/profile",
success: function (response) {
if ($(e.target).hasClass('profile')) {
$('.display').empty().append(
`
<p id="welcome">Bonjour, <em><strong>${response['currentUser']['username']}</strong></em> vous êtes enregistré sous le nom de <strong>${response['currentUser']['firstname']} ${response['currentUser']['lastname']}</strong>.
<br>
Votre adresse email est : <strong>${response['currentUser']['email']}</strong>.
<br>
Pour modifiez vos informations veuillez cliquez sur le menu de navigation.
</p>`);
} else if ($(e.target).hasClass('security')) {
$('.display').empty().append(response['formAccountSettingsView']['content']);
} else if ($(e.target).hasClass('informations')) {
$('.display').empty().append(response['formPersonnalSettingsView']['content'])
}
}
})
});
The problem now is that I don't know how to handle thoses forms from another controller and validate it with the constraints I set on my entity User this is how I validate :
public function editCredentials(Request $request, UserPasswordEncoderInterface $encoder)
{
$user = $this->getUser();
$formPersonnalSettings = $this->createForm(PersonnalSettingsType::class, $user);
if ($request->isMethod('POST')) {
if ($request->request->has('personnal_settings')) {
if ($formPersonnalSettings->isSubmitted() && $formPersonnalSettings->isValid()) {
$user->setFirstname($request->request->get('personnal_settings')['firstname']);
$user->setLastname($request->request->get('personnal_settings')['lastname']);
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->addFlash('personnal_success', 'Vos informations personnels ont bien été enregistrées !');
return $this->redirectToRoute('user_profile');
}
}
Is that a good method? should I handle everything with ajax ? Thanks for your time !
You should use the handlerequest which automatically sets the values in the form to the entity added to it once the form has been submitted.
$form = $this->createCreateForm($entity); // private function to create the form
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
}
}
return $response;
Once handled you just need to return an ok response, or return the form back to the view if something has gone wrong.
If I remember well, the asserts set on the entity are also automatically processed with the handleRequest(), it depends on how you declared them.
Yo can also add other errors after the submit, just add them between the isSumbmitted() and isValid(). Documentation
I leave you here some documentation that may help.
Handle request
Validation
Validation in the form itself
I'm a PHP/JS novice, and love to learn more about coding. Today I need your help (pretty please!)
I'm currently trying to add a dropdown option on a Woocommerce checkout so visitors can say where they found us.
So I used a snippet a programmer already coded and tweaked it a little bit.
The only think quite different between my website and his was that he used Polylang and I'm not (unilingual website).
Everything works except the admin dashboard doesn't display the right info :
https://i.imgur.com/JYLmTaz.png
In my orders, I expect to have just one entry (1x "Bouche à oreille"). Not that.
Here what I did to have this result :
FUNCTIONS.PHP
/**
add_action('admin_enqueue_scripts', 'kantaloup_admin_enqueue');
function kantaloup_admin_enqueue()
{
//wp_enqueue_style('kantaloup', get_template_directory_uri() . '/style.css');
wp_enqueue_script('chart', get_stylesheet_directory_uri() . '/js/Chart.bundle.min.js');
}
function get_order_references_fields($return = '')
{
if($return == 'keys'){
return array(
('Bouche à oreille'),
('Médias sociaux'),
('Moteurs de recherche (Google, Bing...)'),
('Livre/Magazine'),
('Partenaire'),
('Autre'),
);
}
return array(
('Bouche à oreille') => 'Bouche à oreille',
('Médias sociaux') => 'Médias sociaux',
('Moteurs de recherche (Google, Bing...)') => 'Moteurs de recherche (Google, Bing...)',
('Livre/Magazine') => 'Livre/Magazine',
('Partenaire') => 'Partenaire',
('Autre') => 'Autre',
);
}
/*
* Checkout fields: Add
*/
add_action('woocommerce_checkout_fields', 'custom_fields_at_checkout');
function custom_fields_at_checkout($fields)
{
$fields['billing']['referred_by'] = array(
'label' => __('Où nous avez-vous entendu parler de nous?'),
'placeholder' => '',
'required' => true,
'class' => array('referred-by-checkout-field-input form-row-wide'),
'clear' => true,
'type' => 'select',
'options' => get_order_references_fields()
);
return $fields;
}
/*
* Checkout fields: Validate
*/
/*
add_action('woocommerce_checkout_process', 'custom_fields_at_checkout_validate');
function custom_fields_at_checkout_validate()
{
if(! $_POST['referred-by']){
wc_add_notice(__('Veuillez remplir le champ «Où nous avez-vous entendu parler de nous?»'), 'error');
}
}
*/
/*
* Checkout fields: Add to order meta
*/
add_action('woocommerce_checkout_update_order_meta', 'custom_fields_at_checkout_add_to_order_meta');
function custom_fields_at_checkout_add_to_order_meta($order_id)
{
if(! empty($_POST['referred_by']) )
{
update_post_meta($order_id, 'referred_by', sanitize_text_field($_POST['referred_by']) );
}
}
/*
* Checkout fields: Add to order admin page
*/
add_action('woocommerce_admin_order_data_after_billing_address', 'custom_fields_at_checkout_add_to_order_admin_page', 10, 1);
function custom_fields_at_checkout_add_to_order_admin_page($order)
{
echo '<p><strong>' . __('Où nous avez-vous entendu parler de nous?') . ' :</strong><br>' . get_post_meta($order->id, 'refered_by', true) . '</p>';
}
/*
* Add admin page for support tab
*/
add_action('admin_menu', 'create_order_report_admin_menu');
function create_order_report_admin_menu()
{
$title = "Rapport de références";
add_menu_page($title, $title, 'manage_options', 'sales-type-report', 'sales_type_report', '', '3.1');
function sales_type_report()
{
include(get_stylesheet_directory() . '/includes/admin/sales-report.php');
}
}
/*
* Get order references and return json object
*/
function get_order_references_json()
{
$references = get_order_references_fields();
/*
* Build the labels
*/
$the_labels = [];
foreach($references as $slug => $label)
{
$the_labels[] = $label;
}
/*
* Build the datasets
*/
$the_datasets = [];
$this_dataset = new stdClass();
$this_dataset->label = ['Nombre de commandes'];
$this_dataset->backgroundColor = ['#CFF09E', '#A8DBA8', '#79BD9A', '#3B8686', '#0B486B', '#1B6995', '#1E81B9', '#88AABD'];
$this_dataset->borderColor = ['#CFF09E', '#A8DBA8', '#79BD9A', '#3B8686', '#0B486B', '#1B6995', '#1E81B9', '#88AABD'];
$this_dataset->borderWidth = 2;
$orders = get_posts(
array(
'post_type' => 'shop_order',
'posts_per_page' => -1,
'post_status' => 'closed, wc-on-hold'
)
);
if( empty($orders) ) return;
$the_datasets_bars = [];
foreach($orders as $order){
$reference_meta = get_post_meta($post->ID, 'referred_by', true);
if(! empty($reference_meta) ){
foreach($references as $slug => $label)
{
if($slug == $reference_meta){
$the_datasets_bars[$slug] = ! isset($the_datasets_bars[$slug]) ? 0 : ++$the_datasets_bars[$slug];
}
}
}
}
$correct_order = get_order_references_fields('keys');
$correctly_ordered_dataset_bars = array_merge(array_flip($correct_order), $the_datasets_bars);
$this_dataset->data = array_values($correctly_ordered_dataset_bars);
$the_datasets[] = $this_dataset;
/*
* Build the final array
*/
$data = array(
'labels' => $the_labels,
'datasets' => $the_datasets
);
return json_encode($data);
}
In includes/admin/sales-report.php :
<style>
.sep{
margin:40px 0;
}
.excerpt:after {
content: "";
display: table;
clear: both;
}
.excerpt img{
display:block;
margin: 30px 0;
max-width: 1024px;
width: auto;
border: 1px solid #ddd;
padding: 10px;
background: #fff;
}
.top{
float:right;
}
ol ol{
margin-top: 10px;
}
</style>
<script>
(function($){
$(document).ready(function () {
var ctx = $('#the-sales-references-table');
var myChart = new Chart(ctx, {
type: 'bar',
data: <?= get_order_references_json(); ?>,
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
});
}(jQuery));
</script>
<div class="wrap">
<h1>Rapport des références sur les commandes</h1>
<div class="wrap">
<canvas id="the-sales-references-table"></canvas>
</div>
<? get_order_references_json(); ?>
</div>
I also added chart.js in child theme (this part is working).
Thanks a lot for your help
After checking and testing your code, here are a few points that caused the issue you identify in the screenshot.
The array of data passed to the Chart was empty, which is why you have this "stair"-like pattern. It seems to be how ChartJS.org displays data when it's empty (maybe it defaults to some internal data).
The data were empty because it is not possible to pass a PHP function directly in the JavaScript (data: <?= get_order_references_json(); ?>). By testing it in the browser, the 'data' variable was empty and caused an error. Instead, what I did is to use WordPress's wp_localize_script to run the function beforehand in PHP and then pass the json_encoded data as a JS variable. Using that approach, it's possible to then JSON.parse the JS variable directly in the data variable. If more data was in play, it would be best to use AJAX requests to dedicated PHP functions.
Even if the data were not empty, you would still get the "stair"-like pattern because if only a few of the 'references' were present, the others would be empty and thus cause the "stair"-like pattern. To fix that, I prefill the array with zeroes (0s) in all slots before assigning them. $the_datasets_bars = array_fill_keys(array_keys($references), 0); This works.
There were a few minor issues I fixed that prevented the code from running in my test WP environment.
Here's the modified code with comments in ALL CAPS:
functions.php
<?php
/**
* Plugin Name: My Plugin
* Description: Custom features.
* Version: 2019.1.0.0
*/
/*
* kantaloup enqueue
*/
add_action('admin_enqueue_scripts', 'kantaloup_admin_enqueue');
function kantaloup_admin_enqueue()
{
//wp_enqueue_style('kantaloup', get_template_directory_uri() . '/style.css');
wp_enqueue_script('chart', plugin_dir_url(__FILE__) . 'js/Chart.bundle.min.js');
// FIX: need to pass the data to the client-side so they can be accessible via JS
wp_localize_script('chart', 'test', array(
'data' => get_order_references_json()
));
}
function get_order_references_fields($return = '')
{
if($return == 'keys'){
return array(
('Bouche à oreille'),
('Médias sociaux'),
('Moteurs de recherche (Google, Bing...)'),
('Livre/Magazine'),
('Partenaire'),
('Autre'),
);
}
return array(
('Bouche à oreille') => 'Bouche à oreille',
('Médias sociaux') => 'Médias sociaux',
('Moteurs de recherche (Google, Bing...)') => 'Moteurs de recherche (Google, Bing...)',
('Livre/Magazine') => 'Livre/Magazine',
('Partenaire') => 'Partenaire',
('Autre') => 'Autre',
);
}
/*
* Checkout fields: Add
*/
add_action('woocommerce_checkout_fields', 'custom_fields_at_checkout');
function custom_fields_at_checkout($fields)
{
$fields['billing']['referred_by'] = array(
'label' => __('Où nous avez-vous entendu parler de nous?'),
'placeholder' => '',
'required' => true,
'class' => array('referred-by-checkout-field-input form-row-wide'),
'clear' => true,
'type' => 'select',
'options' => get_order_references_fields()
);
return $fields;
}
/*
* Checkout fields: Validate
*/
/*
add_action('woocommerce_checkout_process', 'custom_fields_at_checkout_validate');
function custom_fields_at_checkout_validate()
{
if(! $_POST['referred-by']){
wc_add_notice(__('Veuillez remplir le champ «Où nous avez-vous entendu parler de nous?»'), 'error');
}
}
*/
/*
* Checkout fields: Add to order meta
*/
add_action('woocommerce_checkout_update_order_meta', 'custom_fields_at_checkout_add_to_order_meta');
function custom_fields_at_checkout_add_to_order_meta($order_id)
{
if(! empty($_POST['referred_by']) )
{
update_post_meta($order_id, 'referred_by', sanitize_text_field($_POST['referred_by']) );
}
}
/*
* Checkout fields: Add to order admin page
*/
add_action('woocommerce_admin_order_data_after_billing_address', 'custom_fields_at_checkout_add_to_order_admin_page', 10, 1);
function custom_fields_at_checkout_add_to_order_admin_page($order)
{
// FIX: there was an error accessing $order->id; need to use the get_id()
echo '<p><strong>' . __('Où nous avez-vous entendu parler de nous?') . ' :</strong><br>' . get_post_meta($order->get_id(), 'referred_by', true) . '</p>';
}
/*
* Add admin page for support tab
*/
add_action('admin_menu', 'create_order_report_admin_menu');
function create_order_report_admin_menu()
{
$title = "Rapport de références";
add_menu_page($title, $title, 'manage_options', 'sales-type-report', 'sales_type_report', '', '3.1');
}
// FIX: separated the function to be outside of the above function
function sales_type_report()
{
include('includes/admin/sales-report.php');
}
/*
* Get order references and return json object
*/
function get_order_references_json()
{
$references = get_order_references_fields();
/*
* Build the labels
*/
$the_labels = [];
foreach($references as $slug => $label)
{
$the_labels[] = $label;
}
/*
* Build the datasets
*/
$the_datasets = [];
$this_dataset = new stdClass();
$this_dataset->label = ['Nombre de commandes'];
$this_dataset->backgroundColor = ['#CFF09E', '#A8DBA8', '#79BD9A', '#3B8686', '#0B486B', '#1B6995', '#1E81B9', '#88AABD'];
$this_dataset->borderColor = ['#CFF09E', '#A8DBA8', '#79BD9A', '#3B8686', '#0B486B', '#1B6995', '#1E81B9', '#88AABD'];
$this_dataset->borderWidth = 2;
$orders = get_posts(
array(
'post_type' => 'shop_order',
'posts_per_page' => -1, // required to allow >5 results
'post_status' => array_keys( wc_get_order_statuses() )
)
);
// print_r($orders);
if( empty($orders) ) return;
// FIX: (fill in all keys; otherwise, we get the stair effect)
$the_datasets_bars = array_fill_keys(array_keys($references), 0);
foreach($orders as $order){
// FIX: MUST be $order->ID (Post->ID), not 'id'
$reference_meta = get_post_meta($order->ID, 'referred_by', true);
echo $reference_meta . "\n";
if(! empty($reference_meta) ){
foreach($references as $slug => $label)
{
if($slug == $reference_meta){
$the_datasets_bars[$slug] = ! isset($the_datasets_bars[$slug]) ? 0 : ++$the_datasets_bars[$slug];
}
}
}
}
// FIX: some debug logs
echo "THE_DATASETS_BARS\n";
print_r($the_datasets_bars);
echo "\n";
$correct_order = get_order_references_fields('keys');
$correctly_ordered_dataset_bars = array_merge(array_flip($correct_order), $the_datasets_bars);
$this_dataset->data = array_values($correctly_ordered_dataset_bars);
$the_datasets[] = $this_dataset;
/*
* Build the final array
*/
$data = array(
'labels' => $the_labels,
'datasets' => $the_datasets
);
// FIX: added JSON_UNESCAPED_UNICODE; otherwise, French accents are mishandled
return json_encode($data, JSON_UNESCAPED_UNICODE);
}
includes/admin/sales-report.php
<style>
.sep{
margin:40px 0;
}
.excerpt:after {
content: "";
display: table;
clear: both;
}
.excerpt img{
display:block;
margin: 30px 0;
max-width: 1024px;
width: auto;
border: 1px solid #ddd;
padding: 10px;
background: #fff;
}
.top{
float:right;
}
ol ol{
margin-top: 10px;
}
</style>
<script>
let $ = jQuery
// FIX: the way this method was launched caused problems when loading in browser;
// there were nested 'document.ready' functions
$(function() {
console.warn("data", test);
var ctx = $('#the-sales-references-table');
console.info(ctx);
var myChart = new Chart(ctx[0].getContext('2d'), {
type: 'bar',
// FIX: parse data from the PHP-generated JS data variable
data: JSON.parse(test.data),
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
})
</script>
<div class="wrap">
<h1>Rapport des références sur les commandes</h1>
<div class="wrap">
<canvas id="the-sales-references-table"></canvas>
</div>
<!-- FIX (remove the PHP function) -->
</div>
hi guys i am working on forget password in mobile app using nativescript, and i want to show alert message when the user insert wrong email or wrong apssword in the dialog , but i couldn't make it is there any body can help ?
let options: PromptOptions = {
title: "Entrez votre nouveau mot de passe",
okButtonText: "Suivant",
cancelButtonText: "Annuler",
cancelable: true,
inputType: inputType.password,
capitalizationType: capitalizationType.none
}; prompt(options).then((pass: PromptResult) => {
if (pass.text && pass.result == true) {
let options: PromptOptions = {
title: "Entrez votre nouveau mot de passe de nouveau",
okButtonText: "Suivant",
cancelButtonText: "Annuler",
cancelable: true,
inputType: inputType.password,
capitalizationType: capitalizationType.none
}; prompt(options).then((pass2: PromptResult) => {
if (pass2.text && pass2.result == true) {
if (pass.text == pass2.text) {
this.auth.resetMDP(this.email, this.code, pass2)
.then((res: any) => {
if (res.message == 'OK')
alert('votre mot de passe a été changé avec succès')
}).catch((err: any) => { alert(err); })
} else alert("re-entrez le mot de passe correctement s'il vous plait");
}
})
}
});
because i ve tried to make it work , but the dialog always close
In my apps I use modals to handle custom dialog styling and special action (as you require validation without closing the dialog). The easiest is:
This is how you call it:
page.showModal(
"you/path/to/modal/directory",
{
// your binding context
},
() => {
// on close callback
}
);
Assume that you have modal layout as XML and code behind (in my case Typescript):
<Page xmlns:RL="nativescript-ripple" xmlns="http://schemas.nativescript.org/tns.xsd" shownModally="onShownModally" >
<DockLayout stretchLastChild="false">
<Label dock="top" text="Hello Modal!!" horizontalAlignment="center" />
<TextView dock="top" text="{{ message }}" fontSize="15sp" horizontalAlignment="left" />
<Button dock="bottom" text="OK" tap="onOkTap" />
</DockLayout>
let closeCallback: () => void;
export function onShownModally(args: any) {
const page: Page = <Page>args.object;
const context = args.context;
// your close callback logic that you passed
closeCallback = args.closeCallback;
// bind you context object to modal
page.bindingContext = fromObject(context);
}
export function onOkTap(args: EventData) {
const page = args.object as Page;
if (closeCallback !== null && closeCallback !== undefined) {
closeCallback();
} else {
page.closeModal();
}
}