app.js
'use strict';
const compression = require('compression');
const express = require('express');
const next = require('next');
const path = require('path');
const fetch = require('isomorphic-fetch');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const auth = '...';
const site = 'help-*-*';
const server = express();
class GetHelp {
constructor() {
this.initApp();
}
/*
Start express application and express healthcheck.
*/
initApp() {
app.prepare().then(() => {
/*
* API Server
*/
server.get('/api/search/:searchTerm', (req, res, next) => {
const searchTerm = req.params.searchTerm;
var endpoint = `services/rest/connect/v1.3/analyticsReportResults`;
fetch(
`https://${auth}@${site}.....com/${endpoint}`, {
method: 'POST',
mode: 'no-cors',
body: JSON.stringify({
"id": 178394,
"filters": [{
"name": "os_search",
"values": [
searchTerm
]
}]
})
})
.then(function(res) { return res.json(); })
.then(function(data) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ article: data }));
});
});
server.get('/api/article/:articleId', (req, res, next) => {
const articleId = req.params.articleId;
var endpoint = "";
if (parseInt(articleId)) {
endpoint = `/services/rest/connect/v1.3/answers/${articleId}/?fields=solution,summary`;
} else {
endpoint = `/services/rest/connect/v1.3/queryResults/?query=select summary,solution from answers where customFields.c.slug='${articleId}'and customFields.c.lang_id=2035 and language=1 and AccessLevels.NamedIDList.ID=11`;
}
fetch(
`https://${auth}@${site}.....com/${endpoint}`, {
method: 'GET',
mode: 'no-cors',
})
.then(function(res) { return res.json(); })
.then(function(data) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ article: data }));
});
});
var endpoint = "services/rest/connect/v1.3/queryResults/?query=select lookupName,value from messageBases ";
endpoint += "where lookupName in (" + msgToGet + ")";
fetch(
`https://${auth}@${site}.....com/${endpoint}`, {
method: 'GET',
mode: 'no-cors',
})
.then(function(res) { return res.json(); })
.then(function(data) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ messageBase: data }));
});
});
/*
* APP Routes
*/
server.get('/search/:searchTerm/page/:page', (req, res) => {
const params = { searchTerm: req.params.searchTerm, page: req.params.page }
return app.render(req, res, '/search', params);
});
server.get('/article/:articleId', (req, res) => {
const params = { articleId: req.params.articleId }
return app.render(req, res, '/article', params);
});
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(8080, 'local-www....dev.com', () => {
this.initHealthcheck();
});
});
}
}
module.exports = new GetHelp();
…
/components/StarRating.js
</pre></pre>
import React from 'react';
import Link from '../components/Link';
import Router from 'next/router'
import 'isomorphic-fetch';
import Modal from 'react-modal';
const site = 'help-en-us';
const customStyles = {
content : {
top: '50%',
left: '50%',
right: 'auto',
bottom: 'auto',
marginRight: '-50%',
transform: 'translate(-50%, -50%)'
}
};
export default class extends React.Component {
constructor(props) {
super(props);
this.state = {
starRating: 0,
articleId: this.props.articleId,
thankYou: false,
showStars: true
};
this.handleStar = this.handleStar.bind(this);
this.submitRating = this.submitRating.bind(this);
this.getToken = this.getToken.bind(this);
this.onKeyPress = this.onKeyPress.bind(this);
this.openModal = this.openModal.bind(this);
this.afterOpenModal = this.afterOpenModal.bind(this);
this.closeModal = this.closeModal.bind(this);
this.cancelModal = this.cancelModal.bind(this);
this.submitAnswerFeedback = this.submitAnswerFeedback.bind(this);
this.getToken = this.getToken.bind(this);
}
async submitRating(rating) {
let result = await $.ajax({
url: `http://${site}.....com/ci/ajaxCustom/submitAnswerRating`,
data: `a_id=${this.props.articleId}&amp;rate=${rating}&amp;options_count=5`,
dataType: 'jsonp',
jsonpCallback: 'submitAnswerRating',
success: function(response){
console.log(response.submitted);
}
});
let flag = await result;
return flag
};
async getToken(rating){
let result = await $.ajax({
url: `http://${site}.....com/ci/ajaxCustom/getNewFormToken`,
data: `formToken=${Math.random().toString(36).substr(2)}`,
dataType: 'jsonp',
jsonpCallback: 'getNewFormToken',
success: function(response){
//console.log(typeof(response.newToken));
return response;
}
});
let token = await result;
return token
};
async submitAnswerFeedback(){
let a_id = this.props.articleId;
let rating = this.state.starRating;
let feedbackMessageValue = this.state.feedbackMessageValue;
let token = this.state.token;
console.log('sAF: ' + token);
let result = await $.ajax({
url: `http://${site}.....com/ci/ajaxCustom/submitAnswerFeedback`,
data: `a_id=${a_id}&amp;rate=${rating}&amp;message=${feedbackMessageValue}&amp;f_tok=${token}`,
dataType: 'jsonp',
jsonpCallback: 'submitAnswerFeedback',
success: function(response){
console.log(response);
}
});
let message = await result;
this.closeModal();
return message
};
async handleStar(rating){
// submit the star rating clicked
let ratingSubmitted = await this.submitRating(rating);
if(rating >= 3){
// submitted, and done
this.setState({
thankYou: true,
starRating: rating,
ratingSubmitted: ratingSubmitted,
showStars: false
})
} else {
// less than 3, so get a token, and open popup
let token = await this.getToken(rating);
console.log('obj: ' + token.newToken);
console.log(typeof(token.newToken));
this.openModal();
this.setState({
thankYou: true,
starRating: rating,
ratingSubmitted: ratingSubmitted,
token: token.newToken,
showStars: false
})
}
}
onKeyPress(e) {
let feedbackMessageValue = e.target.value;
}
onChange(e) {
let feedbackMessageValue = e.target.value;
this.setState({
feedbackMessageValue: feedbackMessageValue
});
}
openModal() {
this.setState({
modalIsOpen: true
});
}
afterOpenModal() {
// references are now sync'd and can be accessed.
this.subtitle.style.color = '#f00';
}
closeModal() {
this.setState({
modalIsOpen: false
});
}
cancelModal() {
this.setState({
modalIsOpen: false,
showStars: true,
thankYou: false
})
}
render () {
const stars = [1,2,3,4,5];
const starRating = this.state.starRating;
const thankYou = this.state.thankYou;
const showStars = this.state.showStars;
return (
<div className="box">
<div className="answerFeedback">
{!thankYou ? <div className="title">Please rate this article:</div> : ""}
{showStars ? ( <div className="starsBox">
{
stars.map((star) => {
return(
<span
key={star}
className={`g72-star ${star<=starRating?'selectedStar':''}`}
onClick={(e) => this.handleStar(star)}>
</span>
)
})
}
</div>) : (<span></span>)
}
{thankYou ? <div className="thankYou">Thank you for your feedback!</div> : ""}
<div> {
//<button onClick={this.openModal}>Open Modal</button> }
<Modal
isOpen={this.state.modalIsOpen}
onAfterOpen={this.afterOpenModal}
onRequestClose={this.closeModal}
style={customStyles}
contentLabel="Example Modal">
<h2 ref = { subtitle => this.subtitle = subtitle }>Provide Additional Information</h2>
<div className = "submittedMessage">Your rating has been submitted, please tell us how we can make this answer more useful.</div>
<div className = "faqQuestion">FAQ Feedback – How can we improve this answer? *</div>
<textarea
className = "feedbackMessage"
id = "feedbackMessage"
name = "feedbackMessage"
rows = "4"
cols = "50"
value = { this.state.feedbackMessageValue }
onKeyPress = { (e) => this.onKeyPress(e) }
onChange={(e) => this.onChange(e)}></textarea>
<div className="formButtons">
<button onClick = { this.submitAnswerFeedback } className="submitButton">Submit</button>
<button onClick = { this.cancelModal } className="cancelButton">Cancel</button>
</div>
</Modal>
</div>
</div>
<style jsx>{`
.answerFeedback .title {
font-weigth: bold;
}
.answerFeedback .g72-star {
font-size: 1.5em;
margin: 5px;
cursor: pointer;
color: #6d6b6b;
}
.answerFeedback .g72-star:hover, .selectedStar{
color: rgb(251, 224, 0) !important;
}
.starsBox {
background: #a09e9e;
border-radius: 10px;
padding: 0 10px;
width: 170px;
text-align: center;
}
.feedbackMessage {
border: 1px solid;
margin: 10px 10px 10px 0;
padding: 10px;
width: 100%;
}
.formButtons {
text-align: right;
}
.submitButton, .cancelButton {
width: 100%;
margin: 0;
padding: 10px;
font-weight: bold;
color: white;
text-transform: uppercase;
border-radius: 3px;
text-align: center;
text-decoration: none;
}
.submitButton {
background-color: rgba(250, 84, 0, 1);
}
.submitButton:hover {
background-color: #666;
}
.cancelButton {
background-color: rgb(153, 153, 153);
}
.cancelButton:hover {
background-color: #666;
}
.submitbutton:hover {
}
`}</style>
</div>
);
}
}
<pre>
Oracle AjaxCustom Service endpoint
function submitAnswerRating()
{
$answerID = $this-&gt;input-&gt;get('a_id');
$rating = $this-&gt;input-&gt;get('rate');
$scale = $this-&gt;input-&gt;get('options_count');
if($answerID){
if($this-&gt;model('Answer')-&gt;rate($answerID, $rating, $scale)){
print "submitAnswerRating({'submitted':'true'})";
}else{
print "submitAnswerRating({'submitted':'false'})";
}
}
}
function getNewFormToken()
{
if($formToken = $this-&gt;input-&gt;get('formToken'))
{
$newToken = Framework::createTokenWithExpiration(0, false);
print "getNewFormToken({'newToken':'" . $newToken . "'})";
}
}
function submitAnswerFeedback()
{
AbuseDetection::check();
$answerID = $this->input->get('a_id');
if($answerID === 'null')
$answerID = null;
$rate = $this->input->get('rate');
$message = $this->input->get('message');
$givenEmail = '...@....com';
$threshold = 3;
$optionsCount = 5;
$formToken = $this->input->get('f_tok');
$incidentResult = $this->model('Incident')->submitFeedback($answerID, $rate, $threshold, null, $message, $givenEmail, $optionsCount);
if($incidentResult->result){
print "submitAnswerFeedback({'ID':'" . $incidentResult->result->ID . "'})";
//$this->_renderJSON(array('ID' => $incidentResult->result->ID));
}else{
if($incidentResult->error){
print "submitAnswerFeedback({'error 2':'" . $incidentResult->error->externalMessage . "'})";
}
}