Chris-Code-Samples

  • About
  • WebApp
  • Sample-1-PHP-JS
  • Sample-2-ReactJS

About My Code Samples

Thank you for your interest in my code samples. I greatly appreciate you taking the time to study my code. I will be glad to answer any further questions you may have. Please open the code samples tabs to review the snippets. In addition, my cover page summarizes my work history and past clients. At any time, you can click the blue button below to return to my cover page.
Every project is different. The sample code below, server architecture, database designs, and other decisions are project specific and may not apply to other projects. I made these particular decisions to coordinate into a specific set of budget, scope, and other constraints.
Shown here are outlines of real world code tasks for a previous project. To demonstrate my work, I outline the goal, identify any issues, and show how I solved these issues. Some code has been hidden to protect private authentication keys. Also these code snippets are only a small part of a much larger platform.
Note: My non-standard naming conventions are derived from over two decades of C# coding. Earlier versions of PHP did not support types, and I was trained in type based languages. Therefore, sometimes I may use a lowercase prefix on some variables as a reminder of their types. However, I can easily adapt to any standard naming convention that a new coding team requires.

Sample WebApp - Voice.club - Writing and Language

All sample code snippets shown here are parts of the Voice Club, a large WebApp for Writers and Language. This WebApp for writers was launched in Spring 2020 and since then has gained a creative international following. The Voice Club WebApp is the primary demonstration of my software engineering work. I focus primarily on WebApps built with WordPress. The Voice club was built from five separate WordPress sites combined together into a cohesive modern platform.
I approach WordPress sites almost like individual servers, offloading resources, so that one individual site does not become bloated. For example, the sample Voice Club platform actually consists of multiple WordPress sites, each serving media content. Each WordPress site hosts a specific type of content, which is then fed into the main site which acts as the client WebApp. In this way the primary client WebApp stays lean, clean, and manageable.
You may wonder why I use WordPress sites as media servers as opposed to standard solutions such as Amazon AWS or Azure hosting. As a matter of fact we do host our shared custom NodeJS API on Azure, and some servers on AWS, but those costs are elastic, and can unexpectedly and exponentially increase with high traffic. Actually our WordPress server host offers "unlimited bandwidth", and "unlimited storage", so within a reasonable amount of traffic, even as our traffic rises, we do not see any rising costs. We realize nothing on the web is truly unlimited, so if traffic increases to a certain point we may need to migrate media servers. However, since WordPress is extremely portable and there are a plethora of hosting options, moving a WordPress media server is a breeze. Also using a common WordPress interface to manage media, allows for seamless and easy switching between the various media servers of our platform.

1. Goal - Image Upload via WordPress API

This code task shown below was a small part of a large WebApp for Writers and Language. The sample code below is one task of a writing contest submission module allowing image uploads. The module should work from a desktop or mobile web browser. Our goal was to build a Word Press reusable block allowing a mobile phone browser to take pictures, then allow the user to upload directly to an image server. I decided to use the WordPress API to transfer and store the image. The design involved two WordPress sites, one which represented the WebApp, and the second which was used for the image server. By offloading images to a remote server, the primary WordPress site becomes more like a smart-client streamlined WebApp.
  • 1.1 - PHP + HTML
  • 1.2 - JS + Axios
  • 1.3 - Guzzle + APIs

Building the Block - PHP Class Object and HTML

Remember, our goal was a Word Press reusable block allowing a mobile phone browser to take pictures, then allow the user to upload directly to an image server. The code below builds the first step in the process, creating the block's main PHP object class, and building the UI Page based on various permissions and business rules.
This block allows uploading media in many various instances throughout the entire WebApp platform. It not only handles images, but also handles MP3 Audio files, as well as Video uploads. In addition there are various settings for allowed file types, image size, and extra functionality available only for the admin user role. All of these various options are controlled and set through the block attributes in the code.
Chris-Code-Sample-1.1
<?php
//sc_media_upload.php
//
//2020.10.17.CT-TODO: - List latest 5 or 10 items from the MediaServer
// - Create New Function to List Media
// - Use this new function to check and see if media is uploaded correctly
//WP API DOC:
// https://developer.wordpress.org/rest-api/reference/media/
// https://developer.wordpress.org/rest-api/reference/media/#list-media
//2021.01.24.CT: -Session-Bug-Fix:
// If you want more info, check the following URL
// https://www.xspdf.com/resolution/53892058.html
//
add_shortcode('sc_media_upload','MediaInit');
//
class cMedia {
public $img_upload_button;
public $s_url_ajax;
public $convert_Api_Key;
//2019.09.16.CT:DONE
public $s_url_CloudConvertAPI;
public $WPAPIUser;
public $WPAPIPassword;
public $WPAPIservice_url;
//2019.10.05.CT:DONE
public $aFileTypesAllowed;
public $aFileTypesAllowedStr;
public $aFileTypesConverted;
public $aFileTypesAllowedJS;
//2019.10.27.CT:DONE
public $sFilename;
//2021.01.25.CT:DONE
public $sURLNextPage;
public $sNextPageLinkText;
public $bCloudConvertEnabled;
public function __construct () {
$this->img_upload_button = plugin_dir_url( __FILE__ ).'sa-upload-button.png';
$this->s_url_ajax = admin_url('admin-ajax.php');
$this->convert_Api_Key = "*****";
$this->s_url_CloudConvertAPI = "https://api.cloudconvert.com/v1/convert";
$this->WPAPIUser = "*****";
$this->WPAPIPassword = "*****";
$this->WPAPIservice_url = "*****/wp-json/wp/v2/media";
//2019.10.05.CT:DONE
// TODO:Future: Possible Values: jpg, png, mp4, mp3
$this->aFileTypesAllowed=array("jpg","JPG","png","PNG","jpeg","JPEG","mp3","MP3","gif","GIF");
$this->aFileTypesConverted=array("jpg","JPG","png","PNG","jpeg","JPEG","gif","GIF");
$this->aFileTypesAllowedJS = implode(",", $this->aFileTypesAllowed);
$this->initAllowedTypes();
//2019.10.27.CT:DONE
$this->sFilename="WPAPI";
}
public function initAllowedTypes() {
$types = '';
foreach($this->aFileTypesAllowed as $type) {
if($types != '')
$types .= ',';
$types .= '.'.$type;
}
$this->aFileTypesAllowedStr = $types;
}
}
//Main Shortcode Function - MediaInit:
//
function MediaInit($atts) {
extract(shortcode_atts(array(
'media_category' => 'Default',
'media_form_id' => '0',
'media_tag' => '2021-XXX-01-XXX',
'next_page_url_slug' => 'TODO-Next-Form-Page',
'next_page_link_text' => 'DONE-Click Here to Continue ->',
'cloud_convert_enabled' => '0',
), $atts));
//2021.01.21.CT - Need a Taxanomy to Prefix the media filename:
//2021.01.25.CT - MediaSubmitKey - Identifies Media to Form Entry
//
// sMediaSubmitKey = FormID-UserId-DateTimeKey
// DateTimeKey = https://www.php.net/manual/en/datetime.formats.compound.php
// DateTimeKey = https://stackoverflow.com/questions/20822821/what-is-a-unix-timestamp-and-why-use-it
// DateTimeKey = Unix Timestamp "@" "-"? [0-9]+ "@1215282385"
//
$sMediaSubmitKey = $media_form_id."-".get_current_user_id()."-".strtotime("now");
//
$sMediaFileNamePrefix =
$media_category
."-KEY-".$sMediaSubmitKey
."-TAG-".$media_tag."-FILE-";
//2021.01.21.CT - Current User Is Admin:
$bCurrentUserIsAdmin = 0;
//
if(current_user_can('administrator')) {
$bCurrentUserIsAdmin = 1;
}
else {
$bCurrentUserIsAdmin = 0;
}
$oMedia = new cMedia();
$oMedia->sFilename = $oMedia->sFilename.'-'.$sMediaFileNamePrefix;
//2021.01.29.CT:
$oMedia->bCloudConvertEnabled = cloud_convert_enabled;
//2021.01.29.CT:TODO - Pseudocode
//Add this code to Guzzle:
// IF ($oMedia->bCloudConvertEnabled = 1)
// Convert File via CloudConvert
// ELSE IF ($oMedia->bCloudConvertEnabled = 0)
// Do NOT ConvertFile (Do not send to CloudConvertAPI)
// Upload Directly to SoftArt MediaServer -> WPAPIservice_url
// END IF
//2021.01.25.CT:TODO: continue_form_url_slug
//ROOT = https://www.voice.club/
//sURLNextPage = ROOT + next_page_url_slug
//
$sURLRoot = "https://www.voice.club/";
$sURLParam_sMediaSubmitKey = "?MediaSubmitKey=".$sMediaSubmitKey;
//
$oMedia->sURLNextPage = $sURLRoot
.$next_page_url_slug
.$sURLParam_sMediaSubmitKey;
$oMedia->sNextPageLinkText = $next_page_link_text;
//
media_Init_Global_JS_Vars(
$oMedia->s_url_ajax,
$oMedia->aFileTypesAllowedStr,
$bCurrentUserIsAdmin);
upload_init($oMedia);
$oMedia_json = json_encode($oMedia);
$_SESSION['oMedia'] = $oMedia_json;
}
function media_Init_Global_JS_Vars(
$sURL_Admin_Ajax,
$aFileTypesAllowedJS,
$bCurrentUserIsAdmin) {
//
$sHTML = <<<HTML
<script type="text/javascript" >
var sa_ajax_url = "$sURL_Admin_Ajax";
var types_str = "$aFileTypesAllowedJS";
var sa_media_upload_file_types = types_str.split(",");
var upload_Image_width_Allowed = 500;
var upload_Image_height_Allowed = 500;
var bCurrentUserIsAdmin = $bCurrentUserIsAdmin;
</script>
HTML;
//
return $sHTML;
}
//2021.01.12.CT: htmlAdminOnly - Only Admin user can see this HTML:
function htmlAdminOnly_GetImageByURL() {
$sHTML = <<<HTML
<div>
<input id="image_path"
type="text"
placeholder="Enter Image URL"
style="width:80%;">
<input id="post_image"
type="button"
class="wpbf-button"
name="post_image"
value="Upload Image">
</div>
HTML;
if(current_user_can('administrator')) {
return $sHTML;
}
else {
return "";
}
//
}
//2021.01.12.CT: htmlAdminOnly - Only Admin user can see this HTML:
function htmlAdminOnly_GetMedia() {
$sHTML = <<<HTML
<div>
<input id="getMedia"
type="button"
class="wpbf-button"
name="getMedia"
value="get media">
</input>
<select id="resultNum"
name="resultNum"
style="width:100px;">
<option value="1">1</option>
<option value="5">5</option>
<option value="10">10</option>
<option value="15">15</option>
</select>
<div id='media'
style="display:none; padding-top:20px;">
</div>
</div>
HTML;
if(current_user_can('administrator')) {
return $sHTML;
}
else {
return "";
}
//
}
function upload_init($oMedia){
//
$htmlAdminOnly_GetImageByURL = htmlAdminOnly_GetImageByURL();
$htmlAdminOnly_GetMedia = htmlAdminOnly_GetMedia();
//
$sHTML = <<<HTML
<!-- 2020.03.31.CT - Text Below Does Not Align -->
<!-- <h3>Select File and Upload:</h3> -->
<form method="post" enctype="multipart/form-data" action="">
<div class="image-upload">
<label for="file-input">
<!-- 2021.01.26.CT-TODO: Replace URL Below with STAFF Image URL -->
<img id="imageUploadButton"
src="*****/sa-upload-button.png" />
</label>
<input id='fileToUpload'
type='file'
name='fileToUpload'
accept='$oMedia->aFileTypesAllowedStr'>
</input>
<div>
<!-- <b>Allowed File Types: $oMedia->aFileTypesAllowedStr </b> -->
<!-- <b>Allowed File Types: jpg, png, mp3, mp4</b> -->
</div>
$htmlAdminOnly_GetImageByURL
</div>
</form>
<div id="progressDivId"
style="display:none;
padding-top:20px;" >
<div id="bar"
class="line stripesLoader"
style="background-position:0%; background-color:green">
</div>
</div>
<div id='msg'
style="display:none; padding-top:20px;">
</div>
<hr>
$htmlAdminOnly_GetMedia
HTML;
//
return $sHTML;
}

JavaScript - Building the JS Tier - Axios

This task requires only a very simple JavaScript UI code, so in this case I chose to use plain vanilla code. Actually the bulk of the work in this task happens at the server tier. Remember, our goal was a Word Press reusable block allowing a mobile phone browser to take pictures, then allow the user to upload directly to an image server.
I generally use either plain JS, sometimes jQuery, and for more complex user interfaces, I may use React JS combined with Kendo React Widgets.
Chris-Code-Sample-1.2

Guzzle + CloudConvert.com API + WordPress API - Integration

The industry standard PHP Guzzle HTTP client library was used for connecting external processes.
One issue we found was after uploading from the mobile web browser, WordPress would store and display the image "sideways". Research found this was a known issue with WordPress, so our fix was to use an image rotation API provided by Cloud Convert. Our final code now offers an optional attribute that allows each image to be rotated and possibly resized.
Finally after optional rotation, and resizing, the image will be uploaded to an external media server via the WordPress API. After we implemented the Cloud Convert API rotation fix, now all images appear normal with their correct rotation orientation intact.
Chris-Code-Sample-1.3
<?php
/*
Plugin Name: sa-wp-guzzle
Description: Voice.club - Guzzle - HTTP Layer
Version: 2020.07.27
Author: SoftArt
*/
//2020.07.27.CT: Composer Lib + sa-wp-guzzle - Production Install:
//------
//COMPOSER - Install -> SSH + SUDO access via PuTTY or CodeAnywhere SSH:
// STEP #1: https://getcomposer.org/download/
// STEP #2:
// SoftArt (CodeAnywhere):$ composer require guzzlehttp/guzzle:^7.0
// Voice.club (production):$ php composer.phar require guzzlehttp/guzzle:^7.0
// STEP #3: Activate Plugin: sa-wp-guzzle
//
// http://docs.guzzlephp.org/en/latest/quickstart.html
//------
// Load Composer
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
//NOTE: SoftArt API - Global URL + Token:
// $_SESSION["sa_api_token"]
// $_SESSION["sa_api_url"]
//Guzzle - Set Global $client (for this plugin):
//
function GuzzleClient() {
$client = new Client([
// Base URI is used with relative requests
'base_uri' => $_SESSION["sa_api_url"],
// You can set any number of default request options.
'timeout' => 2.0,
]);
return $client;
}
//////////
// BEGIN: Guzzle - WordPress Connect to SoftArtAPI --> Get MS-SQL Data
// Connecting WordPress to an External Microsoft SQL Server DB
//////////
//////////
// BEGIN: Guzzle - MediaUpload
// NOTE: Process Uploaded Image using 2 distinct external APIs
// 1. CloudConvert.com - API - to convert, resize, and roate image
// 2. WordPress API - Transfer and Host Final Converted Image
//////////
//2020.11.21.CT:DONE: Move saveFile --> Plugin --> sa_wp_guzzle:
function sa_guzzle_postWPAPIMedia() {
session_start();
//NOTE: Required to Deserialize Class Object from Session
$oMedia_json= $_SESSION['oMedia'];
$oMedia = json_decode($oMedia_json);
$ext;
$img_name;
$img_path;
$post;
if(isset($_FILES['fileToUpload'])) {
$img_name = $_FILES["fileToUpload"]["name"];
$img_path = $_FILES["fileToUpload"]["tmp_name"];
$ext = pathinfo($_FILES['fileToUpload']['name'], PATHINFO_EXTENSION);
$new_name = str_replace($ext,"converted.".$ext,$img_name);
//2020.12.06.CT:CloudConvert API Params: Upload File from PC (local file)
$post =[
[
'name' => 'apikey',
'contents' => $oMedia->convert_Api_Key
],
[
'name' => 'inputformat',
'contents' => $ext
],
[
'name' => 'outputformat',
'contents' => $ext
],
[
'name' => 'input',
'contents' => 'upload'
],
[
'name' => 'filename',
'contents' => $new_name
],
[
'name' => 'converteroptions[auto_orient]',
'contents' => 'true'
],
[
'name' => 'converteroptions[resize]',
'contents' => '500'
],
[
'name' => 'wait',
'contents' => 'true'
],
[
'name' => 'download',
'contents' => 'false'
],
[
'name' => 'file',
'contents' => fopen($img_path, 'r'),
'filename' => $img_name
]
];
}
else if(isset($_POST['image_path'])) {
$img_path = $_POST['image_path'];
$ext = pathinfo($img_path, PATHINFO_EXTENSION);
$img_name = pathinfo($img_path, PATHINFO_FILENAME);
$new_name = str_replace($ext,"converted.".$ext,$img_name);
//2020.12.06.CT:CloudConvert API Params: Upload File from URL
$post =[
[
'name' => 'apikey',
'contents' => $oMedia->convert_Api_Key
],
[
'name' => 'inputformat',
'contents' => $ext
],
[
'name' => 'outputformat',
'contents' => $ext
],
[
'name' => 'input',
'contents' => 'download'
],
[
'name' => 'converteroptions[auto_orient]',
'contents' => 'true'
],
[
'name' => 'converteroptions[resize]',
'contents' => '500'
],
[
'name' => 'wait',
'contents' => 'true'
],
[
'name' => 'download',
'contents' => 'false'
],
[
'name' => 'file',
'contents' => $img_path
]
];
}
else {
exit();
}
if (in_array($ext, $oMedia->aFileTypesAllowed)) {
if ($oMedia->bCloudConvertEnabled == 1 && in_array($ext, $oMedia->aFileTypesConverted)) {
//2020.12.06.CT:Guzzle:
$headers = ['Connection' => 'keep-alive',
'cache-control'=> 'no-cache'];
$client = new Client([
'base_uri' => $oMedia->s_url_CloudConvertAPI
]);
$response = $client->request('POST',
$oMedia->s_url_CloudConvertAPI,
['multipart' => $post, 'headers' => $headers]);
$sBody = $response->getBody()->getContents();
$json = json_decode($sBody);
//
saveFile("http:".$json->output->url, $oMedia->sFilename."-".$json->output->filename,
$oMedia->WPAPIservice_url, $oMedia->WPAPIUser, $oMedia->WPAPIPassword,
$oMedia->sURLNextPage,$oMedia->sNextPageLinkText);
}
else {
saveFile($img_path, $oMedia->sFilename."-".$img_name,
$oMedia->WPAPIservice_url, $oMedia->WPAPIUser, $oMedia->WPAPIPassword,
$oMedia->sURLNextPage,$oMedia->sNextPageLinkText);
}
}
else {
echo '<pre id="msg">';
echo "<font color='red'>This file type (".$ext.") is not supported. </font>";
echo '</pre>';
}
exit();
}
add_action('wp_ajax_postWPAPIMedia', 'sa_guzzle_postWPAPIMedia');
add_action( 'wp_ajax_nopriv_postWPAPIMedia', 'sa_guzzle_postWPAPIMedia');
function saveFile($img_path, $img_name,
$service_url, $_APIUser, $_APIPassword,
$sURLNextPage,$sNextPageLinkText)
{
//$curl = curl_init($service_url);
$data = file_get_contents($img_path);
if($data === false)
{
echo '<pre id="msg"><font color="red">
Error - Contact Admin - Failed to Access the File.
</font></pre>';
}
else
{
$headers = ['cache-control'=> 'no-cache',
'content-disposition'=> 'attachment; filename='.$img_name];
$client = new Client([
'base_uri' => $service_url
]);
$response = $client->request('POST', $service_url,
['body' => $data
, 'headers' => $headers
, 'auth' => [
$_APIUser,
$_APIPassword
]]);
$sBody = $response->getBody()->getContents();
$json = json_decode($sBody);
//2020.03.31.CT: Clean Up Messages for Production:
echo '<pre id="msg">';
if(!empty($json)) {
if(!empty($json->data->status) && $json->data->status != 200)
echo "<font color='red'>Error - Contact Admin</br>".$json->message."</font>";
else {
//2020.03.31.CT:DONE: Pass in Shortcode PARAM - PageToRedirectOnSuccess
$sURL = $sURLNextPage;
echo "<h2><a href='".$sURL."'>$sNextPageLinkText</a></h2>";
}
}
else {
echo "<font color='red'>Error - Contact Admin</font>";
}
echo '</pre>';
}
}
function sa_guzzle_getWPAPIMedia() {
$resultNum = $_GET['resultNum'];
if(is_null($resultNum)) {
$resultNum = 1;
}
$client = new Client([
'base_uri' => 'https://*****/wp-json/wp/v2',
'timeout' => 2.0,
]);
$dataArray = array("per_page"=>$resultNum);
$data = http_build_query($dataArray);
$headers = ['Accept' => 'application/json',
'cache-control'=> 'no-cache'];
try {
$response = $client->request('GET',
'https://*****/wp-json/wp/v2/media?'.$data,
[
'auth' => [
'*****',
'*****'
],
'headers' => $headers
]);
$sBody = $response->getBody()->getContents();
$json = json_decode($sBody);
}
catch ( Exception $e ) {
$json = null;
}
echo '<pre >';
if(!empty($json))
{
foreach($json as $key=>$item)
{
if($item->media_type == "image")
echo '<img src="'.$item->source_url
.'" width="140" height="140" style="padding:10px;"/>';
else if($item->media_type == "file")
echo '<audio controls><source src="'
.$item->source_url.'" type="'
.$item->mime_type.'"></audio>';
if(($key+1)%5 == 0)
echo '</br>';
}
}
else {
echo "<font color='red'>Error - Contact Admin</font>";
}
echo '</pre>';
exit();
}
add_action('wp_ajax_getWPAPIMedia', 'sa_guzzle_getWPAPIMedia');
add_action( 'wp_ajax_nopriv_getWPAPIMedia', 'sa_guzzle_getWPAPIMedia');
//---------------------------
//2020.11.21.CT:END:
//////////
// END: Guzzle - MediaUpload
// WP-API + CloudConvert API
//////////

2. Goal - Kendo ReactJS Grid in WordPress

  • 2.1 - KendoReact

Kendo ReactJS Grid in WordPress

Our goal was to build a ReactJS component which instantiated a Kendo React Data Grid. The next step was to fill this grid with Vocabulary list data from MS-SQL. The last step was to convert this into a Gutenberg reusable code block.
One nice advantage of this module, is that the data is actually not pulled from the default MySQL WordPress database. We decided to pull this Vocabulary from a MS-SQL externally hosted database. We achieved this connection via our custom NodeJS API which is hosted on Azure.
We finally met the goal and published Kendo React widgets into a WordPress WebApp via Gutenberg. We had some issues and conflicts but eventually combined these two technologies successfully.
Chris-Code-Sample-2.1
import * as React from "react";
const Component = React.Component;
import axios from 'axios';
// ES2015 module syntax
import { Button } from '@progress/kendo-react-buttons';
import { Grid, GridColumn as Column } from '@progress/kendo-react-grid';
import { orderBy } from '@progress/kendo-data-query';
import { filterBy } from '@progress/kendo-data-query';
import EditForm from './cVocabForm.jsx';
const EditCommandCell = props => {
return (
<td>
<button
className="k-button k-primary"
onClick={() => props.enterEdit(props.dataItem)}
>
Edit
</button>
</td>
);
};
//DOCS:
/*
2020.09.05.CT:TODO - Edit + Update Grid Row in External Pop-Up Form:
https://www.telerik.com/kendo-react-ui/components/grid/editing/editing-external-form
https://wordpress.stackexchange.com/questions/282163/wordpress-ajax-with-axios/284423
*/
export default class Vocab extends React.Component {
constructor(props) {
super(props);
this.state = {
sort: [
{ field: 'Term', dir: 'asc' }
],
filter: {
logic: "and",
filters: []
},
name: '',
vocab: '',
openForm: false,
editItem: {}
};
this.GetVocabData = this.GetVocabData.bind(this);
}
enterEdit = item => {
this.setState({
openForm: true,
editItem: item
});
};
MyEditCommandCell = props => (
<EditCommandCell {...props} enterEdit={this.enterEdit} />
);
handleSubmit = (event) => {
this.setState({
vocab: this.state.vocab.map(item => {
if (event.ID === item.ID) {
item = { ...event };
}
return item;
}),
openForm: false
});
}
handleCancelEdit = () => {
this.setState({ openForm: false })
}
GetVocabData() {
event.preventDefault();
var params = new URLSearchParams();
params.append('action', 'sa_api_getVoiceVocab');
let sURL_Site = '/';
let sURL_Ajax = sURL_Site+"wp-admin/admin-ajax.php";
axios.post(sURL_Ajax, params)
.then(res => {
console.log(res);
this.dataRecieved(res.data);
});
//2020.03.23.CT-TODO: res.data --> Fill data into the grid below:
}
componentDidMount() {
var params = new URLSearchParams();
params.append('action', 'sa_api_getVoiceVocab');
let sURL_Site = '/';
let sURL_Ajax = sURL_Site+"wp-admin/admin-ajax.php";
axios.post(sURL_Ajax, params)
.then(res => {
console.log(res);
//this.setState({ vocab: res.data});
this.dataRecieved(res.data);
});
}
dataRecieved(items) {
this.setState({
...this.state,
vocab: items
});
}
render() {
return (
<React.Fragment>
<form onSubmit={this.GetVocabData}>
<Button primary={true}
type="submit">
Get Vocab Data
</Button>
</form>
<hr></hr>
<Grid
style={{ height: '300px' }}
data={orderBy(filterBy([...this.state.vocab], this.state.filter), this.state.sort)}
sortable={true}
sort={this.state.sort}
onSortChange={(e) => {
this.setState({
sort: e.sort
});
}}
filterable
filter={this.state.filter}
onFilterChange={(e) => {
this.setState({
filter: e.filter
});
}}
>
<Column field="ID" title="ID" width="70px" sortable={true} filterable={false}/>
<Column field="Term" title="Term" width="120px" sortable={true}/>
<Column field="LexicalClass" title="LexicalClass" width="140px" sortable={true} filterable={false}/>
<Column field="Definition" title="Definition" sortable={false} filterable={false}/>
<Column field="Sentence" title="Sentence" sortable={false} filterable={false}/>
<Column cell={this.MyEditCommandCell} sortable={false} filterable={false} />
</Grid>
{this.state.openForm &&
<EditForm
cancelEdit={this.handleCancelEdit}
onSubmit={this.handleSubmit}
item={this.state.editItem}
/>
}
</React.Fragment>
)
}
}
Scroll to Top