Prestashop 1.7 Hook admin product does not display - hook

I have a module on Prestashop that works on versions 1.6 and 1.7.
In version 1.6, I managed to display an additional field on the product sheet in the bacok office. I wish to do the same for version 1.7, but without success for now ...
I try with the displayAdminProductsMainStepLeftColumnMiddle hook
my controller of the module:
public function displayAdminProductsMainStepLeftColumnMiddle($params) {
$product = new Product($params['id_product']);
$this->context->smarty->assign(array(
'id_product_jshop' => $product->id_product_jshop
)
);
return $this->display(__FILE__, '/views/templates/1.7/admin/jshop.tpl');
The recording of the hook
$this->registerHook('displayAdminProductsMainStepLeftColumnMiddle');
and my view:
<div class="m-b-1 m-t-1">
<h2>{l s='Custom Attribute from module' mod='jshopimport'}</h2>
<fieldset class="form-group">
<div class="col-lg-12 col-xl-4">
<label class="form-control-label">{l s='ID JSHOP' mod='jshopimport'}</label>
<input type="text" name="id_product_jshop" class="form-control" {if $id_product_jshop && $id_product_jshop != ''}value="{$id_product_jshop}"{/if}/>
</div>
</fieldset>
<div class="clearfix"></div>
</div>
Have you an idea what is wrong?

The function must to start with "hook" and
public function hookDisplayAdminProductsMainStepLeftColumnMiddle($params)
and then you registering without hook
$this->registerHook('displayAdminProductsMainStepLeftColumnMiddle');

For information, I found my error.
Before I was done in my install function :
$this->registerHook('displayAdminProductsMainStepLeftColumnMiddle'));
return parent::install();
With this solution, the hook was nor registered !!
The goot practice is :
if (!parent::install()
|| !$this->registerHook('displayAdminProductsExtra')
|| !$this->registerHook('displayAdminProductsMainStepLeftColumnMiddle')) {
return false;
}
It is important to do first
parent::install()

Related

"Function Query.where() called with invalid data. Unsupported field value: undefined" Error in angular with firebase

I am using angular to create a booking web app using firebase. I am trying to query through the firebase data and filter them to avoid duplicate bookings to be recorded at the same time slots, but I keep getting the error Function Query.where() called with invalid data. Unsupported field value: undefined. I am new to angular and firebase and this is my first project as well. I could really use some help on this.
checkTimeSlot(){
this.formData.date_time = this.formData.bookDate + "_"+ this.formData.timeSlot;
const queryTimeRefUFC = this.afs
.collection("ufc", ref => ref.where("date_time", "==", this.formData.date_time))
.get();
if (queryTimeRefUFC == null){
console.log("true");
return true;
}
else{
console.log("false");
return false;
}}
This is the method in the component.ts where I created the query search. This method is called when the value in the select input changes.
submitBookingUFC() {
this.formData.fullName = this.user.name;
this.formData.userID = this.user.id;
this.formData.date_time = this.formData.bookDate + "_"+ this.formData.timeSlot;
if (this.checkTimeSlot() == true){
alert("The Time Slot you have selected has already been taken. Please select another.");
}
else if (this.checkTimeSlot() == false){
console.log(this.formData.date_time);
this.crudApi.SaveBookingUFC(this.formData);
alert("Record Saved Successfully");
this.ResetFormUFC(); // Reset form when clicked on reset button
} }
This is the method called when the user clicks the submit button.
<div>
<input
type="date"
class="in-bdate"
id="dateUFC"
name="dateUFC"
[min]="today"
max="{{bookMax}}"
value="{{formData.bookDate}}"
[(ngModel)]="formData.bookDate"
#dateUFC="ngModel"
required>
</div>
<div>
<div style="color:red"
*ngIf="dateUFC.errors && (dateUFC.dirty || dateUFC.touched)">
<p *ngIf="dateUFC.errors.required">
<sup>*</sup>Booking Date is required
</p>
</div>
</div>
<div *ngIf="!dateUFC.errors && (dateUFC.dirty || dateUFC.touched)">
<div>
<label for="timesUFC">Time Slot</label>
</div>
<div>
<select
name="timesUFC"
class="in-tslot"
value="{{formData.timeSlot}}"
(change)="checkTimeSlot()"
[(ngModel)]="formData.timeSlot"
#timeSlotUFC="ngModel"
required>
<option *ngFor="let time of timesUFC" >{{time.name}}</option>
</select>
</div>
<div>
<div style="color:red"
*ngIf="(timeSlotUFC.dirty || timeSlotUFC.touched)">
<p *ngIf="timeSlotUFC.errors && timeSlotUFC.errors.required">
<sup>*</sup>Time Slot is required
</p>
<p [ngModel]="timeError" name="error" ngDefaultControl>{{ timeError }}</p>
</div>
</div>
</div>
This is the html code I used to attain the date for the booking and the time of the booking. Using these I created a composite field as date_time using this.formData.date_time = this.formData.bookDate + "_"+ this.formData.timeSlot; to avoid getting duplicate bookings for the same time slot on the same day. The formData here is linked to a class I created for the entire booking array using formData = new UfcData; where UfcData is the name of the class.
export class UfcData {
docID!: string;
userID!: string;
fullName!: string;
contactNo!: string;
timeSlot!: string;
bookDate!: string;
date_time!: string;}
This is the data in the UfcData class.
This is how my Collection and Documents look like
What I need is to acquire the user's input from the form which is acquire from ngModel to the UfcData class and make sure that there aren't any documents in the cloud firestore with the exact same date and time.
*After tweaking the code a little bit the above error does not display. However the if condition in the checkTimeSlot() method always returns true no matter what the option on the select is.
Thanks in advance.

Livewire and Flatpickr - fails after rerender

This may be a basic question, but I'm struggling. Essentially I have a livewire component that updates an array of flight information that a user enters. Whenever the components get rerendered, the flatpickr functionality stops working entirely. I presume this is because the javascript to initialize the component on that field is not running. What is the best practice to ensure these get rerendered with the appropriate javascript to enable the functionality.
Here's my blade snippet which renders fine on the initial load, but whenever a change to the data occurs, the page re-renders all the flights in the array, but the flatpickr functionality does not work anymore.
<form>
#foreach($flights as $i => $f)
<label
x-data
x-init="flatpickr($refs.input, {
dateFormat: 'Y-m-d H:i',
altInput: true,
altFormat: 'F j, Y h:i K',
enableTime: true,
})">
<div class="form-label">Arrival Time</div>
<div class="relative">
<input type="text"
wire:model="flights.{{ $i }}.ArrivalTime"
wire:key="fl{{ $i }}arrtime"
data-input
x-ref="input"
placeholder="Arrival Time"
value="{{ $f['ArrivalTime']}}"
name="flights[{{ $i }}][ArrivalTime]"
id="ArrivalTime{{$i}}"
/>
</div>
</label>
#endforeach
</form>
The livewire component is basically this:
class Itinerary extends Component
{
public $itin = null;
public $flights = [];
public function render()
{
return view('livewire.itinerary');
}
}
You need to wrap the input in a <div> like this:
<div wire:ignore>
<!-- Your input here -->
</div>
Source: https://laravel-livewire.com/docs/2.x/alpine-js#ignoring-dom-changes

Angular function that does task I can not figure out why it is this function

I have a sample code that is written in angular/node. I pin pointed the function that performs a task. I can not figure out why..or how.
I was able to go through the snippets of code and pin point the record by adding a console.log() and logging out the data so I know the function i found is the correct one i just dont undestand why because in angular it is called "delete()" but in the function it is called "deleteValue()"
This is the angular as you can see the delete(row._id) is the onclick function that gets called.
<div class="card-body">
<ngx-datatable class='material' *ngIf="row" [columnMode]="'force'"
[headerHeight]="40" [footerHeight]="40" [rowHeight]="'50'"
[limit]="500000" [rows]='perm' [scrollbarH]="true"
#table [limit]="_limit" >
<ngx-datatable-column prop="value" name="Name" [width]="130"
[sortable]="true">
<ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
{{row.value}}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column prop="qty" name="Qty" [width]="130"
[sortable]="true">
<ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
{{row.qty}}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column name="Action" [sortable]="false" [width]="75">
<ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
<div class="justify-content-center align-items-center">
<span class="col-md-4">
<button class="btn btn-danger" (click)="delete(row._id)">
Delete
</button>
</span>
</div>
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
This is the nodejs code:
valueController.deleteValue= async (req)=>{
try{
var recordType = await valueModel.deleteValue({_id: req.params.id});
console.log('Deleting record: ' + req.params.id);
return recordType;
} catch(error) {
throw error;
}
}
Thanks,
I was expecting the function to be called delete not deleteValue how does this work?
(click)="delete(row._id)"
Will call a method called delete on the Angular component, we cannot see your Angular TypeScript here but the component would then normally then call an Angular service and that service would then make a http call to your node api.
The click function on a button is not going to directly call the api.

When should we use Vue.js's component

When I study the feature of Vue.js's component system. I feel confused when and where should we use this? In Vue.js's doc they said
Vue.js allows you to treat extended Vue subclasses as reusable
components that are conceptually similar to Web Components, without
requiring any polyfills.
But based on their example it doesn't clear to me how does it help to reuse. I even think it complex the logic flow.
For example, you use "alerts" a lot in your app. If you have experienced bootstrap, the alert would be like:
<div class="alert alert-danger">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<strong>Title!</strong> Alert body ...
</div>
Instead of writing it over and over again, you can actually make it into a component in Vue:
Vue.component('alert', {
props: ['type','bold','msg'],
data : function() { return { isShown: true }; },
methods : {
closeAlert : function() {
this.isShown = false;
}
}
});
And the HTML template (just to make it clear, I separate this from the Vue Comp above):
<div class="alert alert-{{ type }}" v-show="isShown">
<button type="button" class="close" v-on="click: closeAlert()">×</button>
<strong>{{ bold }}</strong> {{ msg }}
</div>
Then you can just call it like this:
<alert type="success|danger|warning|success" bold="Oops!" msg="This is the message"></alert>
Note that this is just a 4-lines of template code, imagine when your app uses lot of "widgets" with 100++ lines of code
Hope this answers..

How can I hide whmcs buttons?

Hi I hope someone can help on the client details page I need to hide the Email forwarding button and the DNS management button if the client has selected custom nameservers. I just can't work it out son any help is much welcomed ..Here is the code that takes the input;
<form method="post" action="{$smarty.server.PHP_SELF}?action=domaindetails">
<input type="hidden" name="sub" value="savens">
<input type="hidden" name="id" value="{$domainid}">
<p><input type="radio" name="nschoice" value="default" id="nschoicedefault" onclick="usedefaultns()"{if $defaultns} checked{/if} /> <label for="nschoicedefault">{$LANG.nschoicedefault}</label><br />
<input type="radio" name="nschoice" value="custom" id="nschoicecustom" onclick="usecustomns()"{if !$defaultns} checked{/if} /> <label for="nschoicecustom">{$LANG.nschoicecustom}</label></p>
And here is the code for the buttons;
{if $emailforwarding}
<td><form method="post" action="{$smarty.server.PHP_SELF}?action=domainemailforwarding">
<input type="hidden" name="domainid" value="{$domainid}">
<p align="center">
<input type="submit" value="{$LANG.domainemailforwarding}" class="button">}
</p>
</form></td>
{/if}
{if $dnsmanagement}
<td><form method="post" action="{$smarty.server.PHP_SELF}?action=domaindns">
<input type="hidden" name="domainid" value="{$domainid}">
<p align="center">
{<input type="submit" value="{$LANG.domaindnsmanagement}" class="button">}
</p>
</form></td>
{/if}
I suggest writing a helper function and calling it at the top of the tpl file
and passing the domain id to it.
You can then use the WHMCS internal API function Domain Nameservers to get the domains nameservers then compare them against the default nameservers in the tblconfiguration in the WHMCS database.
Something like this
{php}
// include our helper php file
require_once(dirname(__FILE__).'/Helper.php');
//get domain id from our template variables
$domainid = $this->get_template_vars('domainid');
//call to our helper function passing the domain ID
$hasCustomeNameServers = Helper::hasCustomNameServers($domainid);
//Once we've compared the nameservers agains the default ones we write
//our binary check to the template
if($hasCustomeNameServers >0){
$this->assign('hasCustomeNameServers',true);}
{/php}
Then in side our Helper.php we have something like the following
<?php
class Helper {
public static function hasCustomNameServers($domainid) {
$isCustom = 0;
//Interal API call to get the domains nameservers
$command = "domaingetnameservers";
$adminuser = "admin";
$values["domainid"] = $domainid;
$results = localAPI($command,$values,$adminuser);
//get default nameservers
$defautName1 ='';
$sql = mysql_query('SELECT value FROM tblconfiguration '.
' WHERE setting = "DefaultNameserver1"');
if ($res = mysql_fetch_assoc($sql)) {
$defautName1 = $res["value"];}
$defautName2 ='';
$sql = mysql_query('SELECT value FROM tblconfiguration '.
' WHERE setting = "DefaultNameserver2"');
if ($res = mysql_fetch_assoc($sql)) {
$defautName2 = $res["value"];}
//compare results
foreach ($results as &$value) {
if($value == $defautName1 || $value == $defautName2){
$isCustom++;
}
}
return $isCustom;
}
}
Now it's simply a matter on the template to wrap the {if $emailforwarding} and the {if $dnsmanagement} blocks around our check {if !hasCustomeNameServers}
I hope this helps you in the right direction this is by no means a comprehensive answer but is a guide towards the approach I think you should take in implementing your solution.

Resources