diff --git a/.idea/webServers.xml b/.idea/webServers.xml
index 472b06c..f312376 100644
--- a/.idea/webServers.xml
+++ b/.idea/webServers.xml
@@ -1,18 +1,18 @@
-
+
-
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 2be28e1..0f0a5cd 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -1,559 +1,548 @@
+
+
+
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
+
+
-
-
-
-
-
-
-
-
+
-
-
+
+
-
-
+
+
-
-
+
+
console
tip
tooltip
url
icon
props.data.
data
ButtonInput
TxtInput
numeric
here
if
UserCost
Url
Icon
Data
UserCostSelect
-
-
+
+
true
true
true
true
DEFINITION_ORDER
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
+
+
-
-
+
+
-
-
-
-
-
-
+
1535982823834
1535982823834
+
+
+
-
+
-
+
+
-
+
-
+
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/css/costcalc.css b/css/costcalc.css
index b2755df..76ce072 100644
--- a/css/costcalc.css
+++ b/css/costcalc.css
@@ -1,84 +1,93 @@
-@media screen and (max-width: 768px) {
- .lead {
- font-size:25px;
+html {
+ font-size: 1rem;
+}
+
+@include media-breakpoint-up(sm) {
+ html {
+ font-size: 1.2rem;
}
}
-@media screen and (max-width: 568px) {
- .lead {
- font-size:0.5em;
+@include media-breakpoint-up(md) {
+ html {
+ font-size: 1.4rem;
}
}
+@include media-breakpoint-up(lg) {
+ html {
+ font-size: 1.6rem;
+ }
+}
#plugin-name{
text-transform: capitalize;
font-size: $h2-font-size;
font-weight: bold;
}
#plugin-number{
font-size: large;
text-decoration: none;
}
#plugin-info{
font-size: large;
text-decoration: none;
text-align: center;
}
#plugin-cost{
text-align: center;
font-size: large;
;
}
#plugin-menu{
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 1em;
}
#plugin-knowmore {
padding-top: 0.1em;
padding-bottom: 0.1em;
padding-left: 0.1em;
padding-right: 0.1em;
}
#plugin-add{
padding-top: 0.1em;
padding-bottom: 0.1em;
padding-left: 0.1em;
padding-right: 0.1em;
}
#ccost{
text-align: center;
font-size: large;
}
#module-name{
font-weight: bold;
}
#provider-selector{
padding-top: 1em;
padding-bottom: 0em;
padding-left: 2em;
padding-right: 0.1em;
}
#component{
padding-top: 1em;
padding-bottom: 1em;
padding-left: 1em;
padding-right: 1em;
}
#infotxt{
text-align: center;
}
#service{
font-size: medium;
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
text-align: center;
}
#ctotal{
text-align: center;
font-size: $h2-font-size;
font-weight: bold;
}
\ No newline at end of file
diff --git a/icons/costcalc.png b/icons/costcalc.png
new file mode 100644
index 0000000..292e3dc
Binary files /dev/null and b/icons/costcalc.png differ
diff --git a/icons/totalcost.png b/icons/totalcost.png
new file mode 100644
index 0000000..be45da6
Binary files /dev/null and b/icons/totalcost.png differ
diff --git a/index.html b/index.html
index 4a2c565..1c28b87 100644
--- a/index.html
+++ b/index.html
@@ -1,60 +1,75 @@
- Cost Calculator (beta)
+ Cost Calculator
-
+
-
Cost Calculator (beta V1.5)
+
+
+
+
+
+
Cost Calculator for Data Management
+
+
- Welcome to our cost calculator this tool will help for ...
+ Welcome to our cost calculator this tool will help researcher/professor to have an estimate of the cost of managing, storing and publishing data.
+
+
+ Many providers are included in the service and you will be able to calculate a cost based on your needs. Total cost is calculated dynamically based on your inputs.
+
+
+ We hope you will enjoy this tool and it will be useful for you.
+
+
diff --git a/js/costcal_export.js b/js/costcal_export.js
index 65fd2c3..d9e3139 100644
--- a/js/costcal_export.js
+++ b/js/costcal_export.js
@@ -1,14 +1,16 @@
function toJSONString( form ) {
let obj = {};
let elements = form.querySelectorAll( "input, select, textarea" );
- for( let i = 0; i < elements.length; ++i ) {
+ console.log(elements);
+ for( var i = 0; i < elements.length; ++i ) {
let element = elements[i];
- let name = element.name;
+ let name = element.id;
let value = element.value;
if( name ) {
+ console.log(name);
obj[ name ] = value;
}
}
return JSON.stringify( obj );
}
diff --git a/js/costcalc_main.js b/js/costcalc_main.js
index c4e8e7c..dd310ab 100644
--- a/js/costcalc_main.js
+++ b/js/costcalc_main.js
@@ -1,1025 +1,1101 @@
'use strict';
// Functions Tools
// ---------------------
// ---------------------
-
-
-
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) {
items.push(props.children(i));
}
return {items}
;
}
function tonumeric (value) {
return parseFloat(
value.toString().replace(/[^0-9\.]+/g, '')
);
}
function tomoney(numeric) {
if (typeof numeric == 'string') {
numeric = parseFloat(numeric);
}
return numeric.toFixed(0).replace(/(\d)(?=(\d{3})+\.)/g, '$1,') + ' '+MainData.Currency;
}
function sum(obj) {
const val=Object.values(obj);
var total = 0;
for (var i = 0; i < val.length; i++) {
total = total + tonumeric(val[i]);
}
return total;
}
// Inputs Definition
// ---------------------
// ---------------------
class AmountInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
const value = this.props.value;
return (
{this.props.name}
Amount : {value} {this.props.unit}
);
}
}
class SelectorInput extends React.Component {
constructor(props) {
super(props);
// this.state={listoptions:this.makelist(props.options)};
this.handleChange = this.handleChange.bind(this);
}
rate(i){
return i;
}
makelist(data){
var listoptions=[];
for (var i = 0; i < data.length; i++) {
listoptions.push({data[i]} );
}
return listoptions;
}
handleChange(select) {
this.props.onChange(select.target.value);
}
makerate(){
if (this.props.rate!=null){
return( Rate : {this.props.rate} {this.props.unit} );}
}
maketitle(title){
const maxstr=20
if (title.length>maxstr){
title=title.substr(0,maxstr)+"...";
}
return title;
}
render() {
return (
{this.props.name}
{this.makerate()}
)
}
}
class MakeknowmoreInput extends React.Component {
constructor(props) {
super(props);
this.state={btnsize:20}
}
render() {
const data = this.props.data;
const n = this.props.n;
if (((data.Url !== '') || (data.Url == null)) && (n === 0)) {
// if (data.Url.length==1){
// return(
// } url={data.Url[0].Url}
// id="btn-plugin-knowmore"
// class="btn-primary btn-sm" tips={"Know more about " + data.Name}/>
// );
// }else {
return (} options={data.Url}
id="btn-plugin-knowmore"
class="btn-primary btn-sm" tips={"Know more about " + data.Name}/>);
//}
}
else{
return null
}
}
}
-
class CheckboxInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state={checked:this.props.defaults};
}
handleChange() {
this.setState({checked: !this.state.checked});
this.props.onChange(!this.state.checked);
}
render() {
return (
{this.props.name}
);
}
}
-
class ButtonHrefInput extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
{this.props.name}
);
}
}
-
class ButtonInputWpop extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state={target:"Modal"+this.props.idp};
}
handleChange() {
const out={n:this.props.n,target:this.state.target};
this.props.onClick(out);
}
render() {
return (
-
+
{this.props.name}
Are you sure you want to suppress this line ?
×
You are removing a item. Please confirm you want to suppress : {this.props.info}
Cancel
Yes I want to remove it
-
+
);
}
}
-
class ButtonInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
this.props.onClick(this.props.n);
}
render() {
return (
-
- {this.props.name}
-
+
+ {this.props.name}
+
);
}
}
-
-
-
class MenuInput extends React.Component {
constructor(props) {
super(props);
this.state={listoptions:this.makelist(props.options)};
}
makelist(data){
var listoptions=[];
for (var i = 0; i < data.length; i++) {
listoptions.push({data[i].Name} );
}
return listoptions;
}
render() {
return (
);
}
}
class TxtInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
return (
{this.props.name}
);
}
}
// Outputs definition
// ---------------------
// ---------------------
class CostOutput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
this.props.onCostChange(this.props.display);
}
render() {
return (
);
}
}
function Textoutput(props){
return(
{props.text}
);
}
// Plugins definition
// ---------------------
// ---------------------
class AmountRatesCost extends React.Component {
constructor(props) {
super(props);
this.state={amount : 1, SelectRate : 0 , Rate : this.props.data.Rates[Object.keys(this.props.data.Rates)[0]]};
this.handleAmountChange = this.handleAmountChange.bind(this);
this.handleRateChange = this.handleRateChange.bind(this);
}
handleAmountChange(amount) {
this.setState({amount: amount});
}
handleRateChange(select) {
this.setState({SelectRate: select});
this.setState({Rate: this.props.data.Rates[Object.keys(this.props.data.Rates)[select]]});
}
render() {
const Amount = this.state.amount;
const Rate=this.state.Rate;
const Cost=this.makecost(Amount,Rate);
return (
);
}
makecost(amount,rate) {
if (amount<=this.props.data.AmountFree){
amount=0;
}
var total=amount*rate;
total=tomoney(total);
this.props.onCostChange(this.props.n,total);
return total;
}
}
class CategoryAmountRatesCost extends React.Component {
constructor(props) {
super(props);
this.state={SelectCat : 0, Cat : this.props.data.Cat[Object.keys(this.props.data.Cat)[0]],
amount : 1, SelectRate : 0 , Rate : this.props.data.Rates[Object.keys(this.props.data.Rates)[0]]};
this.handleCatChange = this.handleCatChange.bind(this);
this.handleAmountChange = this.handleAmountChange.bind(this);
this.handleRateChange = this.handleRateChange.bind(this);
// this.handleCostChange = this.handleCostChange.bind(this);
}
handleAmountChange(amount) {
this.setState({amount: amount});
}
handleRateChange(select) {
this.setState({SelectRate: select});
this.setState({Rate: this.props.data.Rates[Object.keys(this.props.data.Rates)[select]]});
}
handleCatChange(select) {
this.setState({SelectCat: select});
this.setState({Cat: this.props.data.Cat[Object.keys(this.props.data.Cat)[select]]});
}
render() {
const Cat=this.state.Cat;
const Amount = this.state.amount;
const Rate=this.state.Rate;
const Cost=this.makecost(Cat,Amount,Rate);
return (
);
}
makecost(cat,amount,rate) {
if (amount<=this.props.data.AmountFree){
amount=0;
}
var total=cat+amount*rate;
total=tomoney(total);
this.props.onCostChange(this.props.n,total);
return total;
}
}
class CategoryCost extends React.Component {
constructor(props) {
super(props);
this.state={SelectCat : 0, Cat : this.props.data.Cat[Object.keys(this.props.data.Cat)[0]]};
this.handleCatChange = this.handleCatChange.bind(this);
}
handleCatChange(select) {
this.setState({SelectCat: select});
this.setState({Cat: this.props.data.Cat[Object.keys(this.props.data.Cat)[select]]});
}
render() {
const Cat=this.state.Cat;
const Cost=this.makecost(Cat);
return (
);
}
makecost(cat) {
var total=cat;
total=tomoney(total);
this.props.onCostChange(this.props.n,total);
return total;
}
}
class NoneSelect extends React.Component {
constructor(props) {
super(props);
}
render() {
const Cost=tomoney(0);
this.props.onCostChange(this.props.n,Cost);
return (
Please select a provider in the list.
);
}
}
class UserCost extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleProviderChange = this.handleProviderChange.bind(this);
this.handleServiceChange = this.handleServiceChange.bind(this);
this.state={total:0,
CostError:false,
ProviderError:true,
ServiceError:true,
};
}
handleChange(value){
if (isNaN(value)||value===''){
console.log("Nan Detected");
this.setState({CostError: true});
value=0;
}else{
this.setState({CostError: false});
}
this.setState({total:value});
this.props.onCostChange(this.props.n,tomoney(value));
}
handleProviderChange(txt){
this.props.handleProviderChange(txt);
if(txt ===''){
this.setState({ProviderError: true});
}
else {
this.setState({ProviderError: false});
}
}
handleServiceChange(txt){
this.props.handleServiceChange(txt);
if(txt ===''){
this.setState({ServiceError: true});
}
else {
this.setState({ServiceError: false});
}
}
classtxt(error){
if(error){
return "is-invalid";
}
else {
return "is-valid";
}
}
render() {
// this.handleChange(this.state.total);
return (
);
}
}
-
-
-
// Combine plugins
// ---------------------
// ---------------------
class ProviderPluginsSelector extends React.Component {
constructor(props) {
super(props);
this.handleCostChange = this.handleCostChange.bind(this);
this.handleProviderChange = this.handleProviderChange.bind(this);
this.handleCommentChange = this.handleCommentChange.bind(this);
this.handleAddPlugin = this.handleAddPlugin.bind(this);
this.handleRmvPlugin = this.handleRmvPlugin.bind(this);
this.handleProviderChangetxt = this.handleProviderChangetxt.bind(this);
this.handleServiceChangetxt = this.handleServiceChangetxt.bind(this);
this.state={
selected:0,
keys:this.ProvidersName(props.data),
- enabled :true,
n:1,
cost:0,
prevcost:0,
comments:"",
Provider:"",
Name:"",
manualname:false,
};
}
handleCostChange(n,e) {
- // console.log("here n : "+n+" e = "+ e);
- if(! this.state.enabled){
- e=0;
- }
if (this.state.prevcost !== e ) {
this.setState({cost: e});
this.setState({prevcost: e});
this.props.handleCostChange(n,e);}
}
handleProviderChange(select){
this.state.Provider='';
this.state.Name='';
this.setState({selected:select});
// this.setState({Cdata:this.cmpdata(this.state.selected)});
// this.setSate({kmm:this.makemenu(this.state.Cdata,0)});
}
handleCommentChange(com){
this.setState({comments:com});
}
handleAddPlugin(n){
this.props.handleAddPlugin(n);
}
handleRmvPlugin(n){
this.props.handleRmvPlugin(n);
}
handleProviderChangetxt(txt){
this.setState({Provider:txt});
}
handleServiceChangetxt(txt){
this.setState({Name:txt});
}
render() {
// console.log("n= "+this.props.n)
const selected=this.state.selected;
this.state.manualname=false;
this.state.keys=this.ProvidersName(this.props.data);
const Cmp=this.cmp2string(this.cmpdata(selected).Style);
const Cdata=this.cmpdata(selected);
const id=this.props.data.Name.replace(/\s/g,'')+this.props.n;
-
-
return(
);
}
cmpdata(select){
let out=this.props.data.Data[select];
if (this.state.manualname){
out.Name=this.state.Name;
- this.state.keys[select]=this.state.Provider;}
+ if ( this.state.Provider ==='') {
+ this.state.keys[select] = 'Please provide a Provider';
+ }else {
+ this.state.keys[select]=this.state.Provider;
+ }
+ }
return out;
}
cmp2string(str){
switch (str) {
case "AmountRatesCost" : return AmountRatesCost;
case "CategoryCost" : return CategoryCost;
case "CategoryAmountRatesCost" : return CategoryAmountRatesCost;
case "NoneSelect":return NoneSelect;
case "UserCost":{this.state.manualname=true; return UserCost;}
}
}
ProvidersName(main){
const data = main.Data;
// console.log(data);
var providers=[];
for (var i = 0; i < data.length; i++) {
providers.push(data[i].Provider);
}
return providers;
}
}
function makeinfo(keys,selected,Cdata){
let name=Cdata.Name;
if ( name ===''&&keys[selected]===''){
name='Please provide a Provider';
return ({name} );
}else if(keys[selected]==='None'){
return ({name} );
}else{
return ({keys[selected]} : {name} );
}
}
class ModuleHeader extends React.Component{
constructor(props) {
super(props);
this.handleAddPlugin = this.handleAddPlugin.bind(this);
this.handleRmvPlugin = this.handleRmvPlugin.bind(this);
}
handleAddPlugin(n){
this.props.handleAddPlugin(n);
}
handleRmvPlugin(n){
this.props.handleRmvPlugin(n);
}
render() {
let minus='';
if (this.props.show_minus){
minus= }
onClick={this.handleRmvPlugin} n={this.props.n} tips={"Remove this line"}
idp={this.props.id} info={this.props.data.Name}/>;
}
return(
- } onClick={this.handleAddPlugin} n={this.props.n} tips={"Add a new "+this.props.data.Name}/>
+ }
+ onClick={this.handleAddPlugin} n={this.props.n} tips={"Add a new "+this.props.data.Name}/>
{minus}
{this.props.n+1}. {this.props.data.Name}
{makeinfo(this.props.keys,this.props.selected,this.props.Cdata)}
{this.props.comments}
);
}
}
+
class ManagePlugins extends React.Component{
constructor(props) {
super(props);
this.handleCostChange = this.handleCostChange.bind(this);
this.handleAddPlugin = this.handleAddPlugin.bind(this);
this.handleRmvPlugin = this.handleRmvPlugin.bind(this);
+ this.handletest = this.handletest.bind(this);
this.state={
displayed:[],
- varsum:{}
+ varsum:{},
+ plugins:[],
};
this.state.displayed.push(this.randomint());
+ this.export=[];
}
handleRmvPlugin(n){
- console.log("remove : "+n);
- console.log(this.state.displayed);
-
$('#'+n.target).modal('hide');
- var tmp=this.state.displayed;
- tmp.splice(n.n,1);
- this.setState({displayed:tmp});
- console.log(this.state.displayed);
+ this.setState({displayed:this.state.displayed.splice(n.n,1)});
this.handleCostChange(n.n,0);
-
}
handleAddPlugin(n){
- var tmp=this.state.displayed;
- tmp.splice(n+1,0,this.randomint());
- this.setState({displayed:tmp});
+ this.setState({displayed:this.state.displayed.splice(n+1,0,this.randomint())});
}
handleCostChange(n,cost) {
this.state.varsum[n]=cost;
this.props.handleCostChange(this.props.n,sum(this.state.varsum));
}
+ handletest(n){
+ console.log(this.export[0])
+ }
+
randomint(){
const tmp=this.state.displayed;
var rnd;
do {
rnd=Math.floor(Math.random() * 100);
var cont=false;
for (let i = 0; i < tmp.length ; i++) {
if (tmp[i]===rnd){
cont=true;
}
}
} while(cont);
return rnd;
}
give_id(index){
return this.state.displayed[index]
}
give_n(){
const disp=this.state.displayed;
return disp.length
}
render() {
let show_minus = false;
if (this.give_n()>1) {
show_minus=true;
}
return(
+
{(index) => }
+ handleCostChange={this.handleCostChange} handleAddPlugin={this.handleAddPlugin}
+ handleRmvPlugin={this.handleRmvPlugin} ref={(input) => {this.export[index] = input }}/>}
- );}
+ {/*
*/}
+
-}
+
+ );}
+}
class PluginsMain extends React.Component {
constructor(props) {
super(props);
this.handleCostChange = this.handleCostChange.bind(this);
this.state={'varsum':{}};
}
handleCostChange(name,e) {
// console.log("name"+name);
this.state.varsum[name]=e;
this.props.TotalCost(sum(this.state.varsum));
}
render() {
return(
{(index) => }
);
}
}
+// MAIN
// ---------------------
// ---------------------
class Main extends React.Component {
constructor(props) {
super(props);
this.handleCostChange = this.handleCostChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.state={'total':0,'prevtotal':0};
this.input = React.createRef();
}
handleCostChange(total) {
// console.log("there total : "+total )
if (this.state.prevtotal !== total){
// console.log("updated :"+total);
// console.log("prev :"+this.state.prevtotal);
this.setState({'total':total});
this.setState({'prevtotal':total});
}
}
handleSubmit(event) {
- alert('A name was submitted: ');
- console.log(event);
+ // alert('A name was submitted: ');
event.preventDefault();
+ console.log(this.input.current);
+
//console.log(this.input)
- var json = toJSONString(this.input);
+ var json = toJSONString(this.input.current);
console.log(json);
}
render() {
return(