mirror of
https://github.com/aclindsa/moneygo.git
synced 2024-12-26 15:42:27 -05:00
Initial JavaScript UI commit
Definitely still a work in progress
This commit is contained in:
parent
524d82ecf7
commit
084ada7e6f
26
static/accounts.js
Normal file
26
static/accounts.js
Normal file
@ -0,0 +1,26 @@
|
||||
// Import all the objects we want to use from ReactBootstrap
|
||||
var ListGroup = ReactBootstrap.ListGroup;
|
||||
var ListGroupItem = ReactBootstrap.ListGroupItem;
|
||||
|
||||
var AccountList = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
};
|
||||
},
|
||||
render: function() {
|
||||
var accounts = this.props.accounts;
|
||||
var account_map = this.props.account_map;
|
||||
|
||||
var listGroupItems;
|
||||
|
||||
for (var i = 0; i < accounts.length; i++) {
|
||||
listGroupItems += <ListGroupItem>{accounts[i].Name}</ListGroupItem>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ListGroup>
|
||||
{listGroupItems}
|
||||
</ListGroup>
|
||||
);
|
||||
}
|
||||
});
|
1
static/external/big/big.min.js
vendored
Normal file
1
static/external/big/big.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
static/external/fonts/rw-widgets.eot
vendored
Normal file
BIN
static/external/fonts/rw-widgets.eot
vendored
Normal file
Binary file not shown.
17
static/external/fonts/rw-widgets.svg
vendored
Normal file
17
static/external/fonts/rw-widgets.svg
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
|
||||
<defs>
|
||||
<font id="rw-widgets" horiz-adv-x="1000" >
|
||||
<font-face font-family="rw-widgets" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
||||
<missing-glyph horiz-adv-x="1000" />
|
||||
<glyph glyph-name="up-dir" unicode="" d="m0 171q0 15 11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26t-10-25-25-10h-500q-15 0-25 10t-11 25z" horiz-adv-x="571.4" />
|
||||
<glyph glyph-name="down-dir" unicode="" d="m0 457q0 15 11 25t25 11h500q14 0 25-11t10-25-10-25l-250-250q-11-11-25-11t-25 11l-250 250q-11 11-11 25z" horiz-adv-x="571.4" />
|
||||
<glyph glyph-name="right-dir" unicode="" d="m0 100v500q0 15 11 25t25 11 25-11l250-250q10-10 10-25t-10-25l-250-250q-11-11-25-11t-25 11-11 25z" horiz-adv-x="357.1" />
|
||||
<glyph glyph-name="left-dir" unicode="" d="m36 350q0 15 10 25l250 250q11 11 25 11t26-11 10-25v-500q0-14-10-25t-26-11-25 11l-250 250q-10 11-10 25z" horiz-adv-x="357.1" />
|
||||
<glyph glyph-name="calendar" unicode="" d="m0-79v715q0 29 21 50t50 21h72v54q0 36 26 63t63 26h36q37 0 63-26t26-63v-54h214v54q0 36 27 63t63 26h35q37 0 63-26t27-63v-54h71q29 0 50-21t22-50v-715q0-29-22-50t-50-21h-786q-29 0-50 21t-21 50z m71 0h161v161h-161v-161z m0 197h161v178h-161v-178z m0 214h161v161h-161v-161z m143 268q0-7 6-13t12-5h36q7 0 12 5t6 13v161q0 7-6 12t-12 6h-36q-7 0-12-6t-6-12v-161z m54-679h178v161h-178v-161z m0 197h178v178h-178v-178z m0 214h178v161h-178v-161z m214-411h179v161h-179v-161z m0 197h179v178h-179v-178z m0 214h179v161h-179v-161z m161 268q0-7 5-13t13-5h35q8 0 13 5t5 13v161q0 7-5 12t-13 6h-35q-8 0-13-6t-5-12v-161z m53-679h161v161h-161v-161z m0 197h161v178h-161v-178z m0 214h161v161h-161v-161z" horiz-adv-x="928.6" />
|
||||
<glyph glyph-name="clock" unicode="" d="m0 350q0 117 58 215t155 156 216 58 215-58 156-156 57-215-57-215-156-156-215-58-216 58-155 156-58 215z m125 0q0-83 41-152t110-111 153-41 152 41 110 111 41 152-41 152-110 111-152 41-153-41-110-111-41-152z m161-54v36q0 8 5 13t13 5h125v196q0 8 5 13t12 5h36q8 0 13-5t5-13v-250q0-7-5-12t-13-5h-178q-8 0-13 5t-5 12z" horiz-adv-x="857.1" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
BIN
static/external/fonts/rw-widgets.ttf
vendored
Normal file
BIN
static/external/fonts/rw-widgets.ttf
vendored
Normal file
Binary file not shown.
BIN
static/external/fonts/rw-widgets.woff
vendored
Normal file
BIN
static/external/fonts/rw-widgets.woff
vendored
Normal file
Binary file not shown.
4
static/external/react-bootstrap/react-bootstrap.min.js
vendored
Normal file
4
static/external/react-bootstrap/react-bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
static/external/react-widgets/loader-big.gif
vendored
Normal file
BIN
static/external/react-widgets/loader-big.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
static/external/react-widgets/loading.gif
vendored
Normal file
BIN
static/external/react-widgets/loading.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 673 B |
1
static/external/react-widgets/react-widgets.css
vendored
Normal file
1
static/external/react-widgets/react-widgets.css
vendored
Normal file
File diff suppressed because one or more lines are too long
5
static/external/react-widgets/react-widgets.js
vendored
Normal file
5
static/external/react-widgets/react-widgets.js
vendored
Normal file
File diff suppressed because one or more lines are too long
34
static/index.html
Normal file
34
static/index.html
Normal file
@ -0,0 +1,34 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>MoneyGo</title>
|
||||
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
|
||||
<link rel="stylesheet" href="static/external/react-widgets/react-widgets.css">
|
||||
<link rel="stylesheet" href="static/stylesheet.css">
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.12.2/react.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.12.2/JSXTransformer.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/globalize/0.1.1/globalize.min.js"></script>
|
||||
<script src="static/external/react-bootstrap/react-bootstrap.min.js"></script>
|
||||
<script src="static/external/react-widgets/react-widgets.js"></script>
|
||||
<script src="static/external/big/big.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="static/utils.js"></script>
|
||||
<script type="text/javascript" src="static/models.js"></script>
|
||||
|
||||
<script type="text/jsx" src="static/top_bar.js"></script>
|
||||
<script type="text/jsx" src="static/accounts.js"></script>
|
||||
<script type="text/jsx" src="static/ui.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center>
|
||||
<div id="content"></div>
|
||||
</center>
|
||||
|
||||
</body>
|
||||
</html>
|
274
static/models.js
Normal file
274
static/models.js
Normal file
@ -0,0 +1,274 @@
|
||||
function getJSONObj(json_input) {
|
||||
if (typeof json_input == "string")
|
||||
return $.parseJSON(json_input)
|
||||
else if (typeof json_input == "object")
|
||||
return json_input;
|
||||
|
||||
console.error("Unable to parse json:", json_input);
|
||||
return null
|
||||
}
|
||||
|
||||
function User() {
|
||||
this.UserId = -1;
|
||||
this.Name = "";
|
||||
this.Username = "";
|
||||
this.Password = "";
|
||||
this.Email = "";
|
||||
}
|
||||
|
||||
var BogusPassword = "password";
|
||||
|
||||
User.prototype.toJSON = function() {
|
||||
var json_obj = {};
|
||||
json_obj.UserId = this.UserId;
|
||||
json_obj.Name = this.Name;
|
||||
json_obj.Username = this.Username;
|
||||
json_obj.Password = this.Password;
|
||||
json_obj.Email = this.Email;
|
||||
return JSON.stringify(json_obj);
|
||||
}
|
||||
|
||||
User.prototype.fromJSON = function(json_input) {
|
||||
var json_obj = getJSONObj(json_input);
|
||||
|
||||
if (json_obj.hasOwnProperty("UserId"))
|
||||
this.UserId = json_obj.UserId;
|
||||
if (json_obj.hasOwnProperty("Name"))
|
||||
this.Name = json_obj.Name;
|
||||
if (json_obj.hasOwnProperty("Username"))
|
||||
this.Username = json_obj.Username;
|
||||
if (json_obj.hasOwnProperty("Password"))
|
||||
this.Password = json_obj.Password;
|
||||
if (json_obj.hasOwnProperty("Email"))
|
||||
this.Email = json_obj.Email;
|
||||
}
|
||||
|
||||
User.prototype.isUser = function() {
|
||||
var empty_user = new User();
|
||||
return this.UserId != empty_user.UserId ||
|
||||
this.Username != empty_user.Username;
|
||||
}
|
||||
|
||||
function Session() {
|
||||
this.SessionId = -1;
|
||||
this.UserId = -1;
|
||||
}
|
||||
|
||||
Session.prototype.toJSON = function() {
|
||||
var json_obj = {};
|
||||
json_obj.SessionId = this.SessionId;
|
||||
json_obj.UserId = this.UserId;
|
||||
return JSON.stringify(json_obj);
|
||||
}
|
||||
|
||||
Session.prototype.fromJSON = function(json_input) {
|
||||
var json_obj = getJSONObj(json_input);
|
||||
|
||||
if (json_obj.hasOwnProperty("SessionId"))
|
||||
this.SessionId = json_obj.SessionId;
|
||||
if (json_obj.hasOwnProperty("UserId"))
|
||||
this.UserId = json_obj.UserId;
|
||||
}
|
||||
|
||||
Session.prototype.isSession = function() {
|
||||
var empty_session = new Session();
|
||||
return this.SessionId != empty_session.SessionId ||
|
||||
this.UserId != empty_session.UserId;
|
||||
}
|
||||
|
||||
var AccountType = {
|
||||
Bank: 1,
|
||||
Cash: 2,
|
||||
Asset: 3,
|
||||
Liability: 4,
|
||||
Investment: 5,
|
||||
Income: 6,
|
||||
Expense: 7
|
||||
}
|
||||
|
||||
function Account() {
|
||||
this.AccountId = -1;
|
||||
this.UserId = -1;
|
||||
this.SecurityId = -1;
|
||||
this.ParentAccountId = -1;
|
||||
this.Type = -1;
|
||||
this.Name = "";
|
||||
this.Children = []; // Not sent across JSON, just used internally
|
||||
}
|
||||
|
||||
Account.prototype.toJSON = function() {
|
||||
var json_obj = {};
|
||||
json_obj.AccountId = this.AccountId;
|
||||
json_obj.UserId = this.UserId;
|
||||
json_obj.SecurityId = this.SecurityId;
|
||||
json_obj.ParentAccountId = this.ParentAccountId;
|
||||
json_obj.Type = this.Type;
|
||||
json_obj.Name = this.Name;
|
||||
return JSON.stringify(json_obj);
|
||||
}
|
||||
|
||||
Account.prototype.fromJSON = function(json_input) {
|
||||
var json_obj = getJSONObj(json_input);
|
||||
|
||||
if (json_obj.hasOwnProperty("AccountId"))
|
||||
this.AccountId = json_obj.AccountId;
|
||||
if (json_obj.hasOwnProperty("UserId"))
|
||||
this.UserId = json_obj.UserId;
|
||||
if (json_obj.hasOwnProperty("SecurityId"))
|
||||
this.SecurityId = json_obj.SecurityId;
|
||||
if (json_obj.hasOwnProperty("ParentAccountId"))
|
||||
this.ParentAccountId = json_obj.ParentAccountId;
|
||||
if (json_obj.hasOwnProperty("Type"))
|
||||
this.Type = json_obj.Type;
|
||||
if (json_obj.hasOwnProperty("Name"))
|
||||
this.Name = json_obj.Name;
|
||||
}
|
||||
|
||||
Account.prototype.isAccount = function() {
|
||||
var empty_account = new Account();
|
||||
return this.AccountId != empty_account.AccountId ||
|
||||
this.UserId != empty_account.UserId;
|
||||
}
|
||||
|
||||
Account.prototype.isRootAccount = function() {
|
||||
var empty_account = new Account();
|
||||
return this.ParentAccountId == empty_account.ParentAccountId;
|
||||
}
|
||||
|
||||
function Split() {
|
||||
this.SplitId = -1;
|
||||
this.TransactionId = -1;
|
||||
this.AccountId = -1;
|
||||
this.Number = "";
|
||||
this.Memo = "";
|
||||
this.Amount = new Big(0.0);
|
||||
this.Debit = false;
|
||||
}
|
||||
|
||||
Split.prototype.toJSONobj = function() {
|
||||
var json_obj = {};
|
||||
json_obj.SplitId = this.SplitId;
|
||||
json_obj.TransactionId = this.TransactionId;
|
||||
json_obj.AccountId = this.AccountId;
|
||||
json_obj.Number = this.Number;
|
||||
json_obj.Memo = this.Memo;
|
||||
json_obj.Amount = this.Amount.toFixed();
|
||||
json_obj.Debit = this.Debit;
|
||||
return json_obj;
|
||||
}
|
||||
|
||||
Split.prototype.fromJSONobj = function(json_obj) {
|
||||
var json_obj = getJSONObj(json_input);
|
||||
|
||||
if (json_obj.hasOwnProperty("SplitId"))
|
||||
this.SplitId = json_obj.SplitId;
|
||||
if (json_obj.hasOwnProperty("TransactionId"))
|
||||
this.TransactionId = json_obj.TransactionId;
|
||||
if (json_obj.hasOwnProperty("AccountId"))
|
||||
this.AccountId = json_obj.AccountId;
|
||||
if (json_obj.hasOwnProperty("Number"))
|
||||
this.Number = json_obj.Number;
|
||||
if (json_obj.hasOwnProperty("Memo"))
|
||||
this.Memo = json_obj.Memo;
|
||||
if (json_obj.hasOwnProperty("Amount"))
|
||||
this.Amount = new Big(json_obj.Amount);
|
||||
if (json_obj.hasOwnProperty("Debit"))
|
||||
this.Debit = json_obj.Debit;
|
||||
}
|
||||
|
||||
Split.prototype.isSplit = function() {
|
||||
var empty_split = new Split();
|
||||
return this.SplitId != empty_split.SplitId ||
|
||||
this.TransactionId != empty_split.TransactionId ||
|
||||
this.AccountId != empty_split.AccountId;
|
||||
}
|
||||
|
||||
var TransactionStatus = {
|
||||
Entered: 1,
|
||||
Cleared: 2,
|
||||
Reconciled: 3,
|
||||
Voided: 4
|
||||
}
|
||||
|
||||
function Transaction() {
|
||||
this.TransactionId = -1;
|
||||
this.UserId = -1;
|
||||
this.Description = "";
|
||||
this.Status = -1;
|
||||
this.Date = new Date();
|
||||
this.Splits = [];
|
||||
}
|
||||
|
||||
Transaction.prototype.toJSON = function() {
|
||||
var json_obj = {};
|
||||
json_obj.TransactionId = this.TransactionId;
|
||||
json_obj.UserId = this.UserId;
|
||||
json_obj.Description = this.Description;
|
||||
json_obj.Status = this.Status;
|
||||
json_obj.Date = this.Date.toJSON();
|
||||
json_obj.Splits = [];
|
||||
for (var i = 0; i < this.Splits.length; i++)
|
||||
json_obj.push(this.Splits[i].toJSONobj());
|
||||
return json_obj;
|
||||
}
|
||||
|
||||
Transaction.prototype.fromJSON = function(json_input) {
|
||||
var json_obj = getJSONObj(json_input);
|
||||
|
||||
if (json_obj.hasOwnProperty("TransactionId"))
|
||||
this.TransactionId = json_obj.TransactionId;
|
||||
if (json_obj.hasOwnProperty("UserId"))
|
||||
this.UserId = json_obj.UserId;
|
||||
if (json_obj.hasOwnProperty("Description"))
|
||||
this.Description = json_obj.Description;
|
||||
if (json_obj.hasOwnProperty("Status"))
|
||||
this.Status = json_obj.Status;
|
||||
if (json_obj.hasOwnProperty("Date")) {
|
||||
this.Date = json_obj.Date
|
||||
if (typeof this.Date === 'string') {
|
||||
var t = Date.parse(this.Date);
|
||||
if (t)
|
||||
this.Date = new Date(t);
|
||||
else
|
||||
this.Date = new Date(0);
|
||||
} else
|
||||
this.Date = new Date(0);
|
||||
}
|
||||
if (json_obj.hasOwnProperty("Splits")) {
|
||||
for (var i = 0; i < json_obj.Splits.length; i++)
|
||||
this.Splits.push(this.Splits[i].fromJSON());
|
||||
}
|
||||
}
|
||||
|
||||
Transaction.prototype.isTransaction = function() {
|
||||
var empty_transaction = new Transaction();
|
||||
return this.TransactionId != empty_transaction.TransactionId ||
|
||||
this.UserId != empty_transaction.UserId;
|
||||
}
|
||||
|
||||
function Error() {
|
||||
this.ErrorId = -1;
|
||||
this.ErrorString = "";
|
||||
}
|
||||
|
||||
Error.prototype.toJSON = function() {
|
||||
var json_obj = {};
|
||||
json_obj.ErrorId = this.ErrorId;
|
||||
json_obj.ErrorString = this.ErrorString;
|
||||
return JSON.stringify(json_obj);
|
||||
}
|
||||
|
||||
Error.prototype.fromJSON = function(json_input) {
|
||||
var json_obj = getJSONObj(json_input);
|
||||
|
||||
if (json_obj.hasOwnProperty("ErrorId"))
|
||||
this.ErrorId = json_obj.ErrorId;
|
||||
if (json_obj.hasOwnProperty("ErrorString"))
|
||||
this.ErrorString = json_obj.ErrorString;
|
||||
}
|
||||
|
||||
Error.prototype.isError = function() {
|
||||
var empty_error = new Error();
|
||||
return this.ErrorId != empty_error.ErrorId ||
|
||||
this.ErrorString != empty_error.ErrorString;
|
||||
}
|
5
static/stylesheet.css
Normal file
5
static/stylesheet.css
Normal file
@ -0,0 +1,5 @@
|
||||
div#content {
|
||||
width: 95%;
|
||||
min-width: 75em;
|
||||
max-width: 100em;
|
||||
}
|
117
static/top_bar.js
Normal file
117
static/top_bar.js
Normal file
@ -0,0 +1,117 @@
|
||||
// Import all the objects we want to use from ReactBootstrap
|
||||
var Alert = ReactBootstrap.Alert;
|
||||
|
||||
var Input = ReactBootstrap.Input;
|
||||
var Button = ReactBootstrap.Button;
|
||||
var DropdownButton = ReactBootstrap.DropdownButton;
|
||||
var MenuItem = ReactBootstrap.MenuItem;
|
||||
|
||||
var Row = ReactBootstrap.Row;
|
||||
var Col = ReactBootstrap.Col;
|
||||
|
||||
var LoginBar = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {username: '', password: ''};
|
||||
},
|
||||
onUsernameChange: function(e) {
|
||||
this.setState({username: e.target.value});
|
||||
},
|
||||
onPasswordChange: function(e) {
|
||||
this.setState({password: e.target.value});
|
||||
},
|
||||
handleSubmit: function(e) {
|
||||
var user = new User();
|
||||
e.preventDefault();
|
||||
user.Username = this.refs.username.getValue();
|
||||
user.Password = this.refs.password.getValue();
|
||||
this.props.onLoginSubmit(user);
|
||||
},
|
||||
handleNewUserSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
this.props.onCreateNewUser();
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<Input wrapperClassName="wrapper">
|
||||
<Row>
|
||||
<Col xs={4}></Col>
|
||||
<Col xs={2}>
|
||||
<Button bsStyle="link"
|
||||
onClick={this.handleNewUserSubmit}>Create New User</Button>
|
||||
</Col>
|
||||
<Col xs={2}>
|
||||
<Input type="text"
|
||||
placeholder="Username..."
|
||||
ref="username"/>
|
||||
</Col>
|
||||
<Col xs={2}>
|
||||
<Input type="password"
|
||||
placeholder="Password..."
|
||||
ref="password" block/>
|
||||
</Col>
|
||||
<Col xs={2}>
|
||||
<Button type="submit" bsStyle="primary" block>
|
||||
Login</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Input>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var LogoutBar = React.createClass({
|
||||
handleOnSelect: function(key) {
|
||||
if (key == 1) {
|
||||
if (this.props.onAccountSettings != null)
|
||||
this.props.onAccountSettings();
|
||||
} else if (key == 2) {
|
||||
this.props.onLogoutSubmit();
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
var signedInString = "Signed in as "+this.props.user.Name;
|
||||
return (
|
||||
<Input wrapperClassName="wrapper">
|
||||
<Row>
|
||||
<Col xs={2}><label className="control-label pull-left">Money<i>Go</i></label></Col>
|
||||
<Col xs={6}></Col>
|
||||
<Col xs={4}>
|
||||
<div className="pull-right">
|
||||
<DropdownButton title={signedInString} onSelect={this.handleOnSelect} bsStyle="info">
|
||||
<MenuItem eventKey="1">Account Settings</MenuItem>
|
||||
<MenuItem eventKey="2">Logout</MenuItem>
|
||||
</DropdownButton>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Input>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var TopBar = React.createClass({
|
||||
render: function() {
|
||||
var barContents;
|
||||
var errorAlert;
|
||||
if (!this.props.user.isUser())
|
||||
barContents = <LoginBar onLoginSubmit={this.props.onLoginSubmit} onCreateNewUser={this.props.onCreateNewUser} />;
|
||||
else
|
||||
barContents = <LogoutBar user={this.props.user} onLogoutSubmit={this.props.onLogoutSubmit} onAccountSettings={this.props.onAccountSettings}/>;
|
||||
if (this.props.error.isError())
|
||||
errorAlert =
|
||||
<Alert bsStyle="danger" onDismiss={this.props.onErrorClear}>
|
||||
<h4>Error!</h4>
|
||||
<p>Error {this.props.error.ErrorId}: {this.props.error.ErrorString}</p>
|
||||
<Button onClick={this.props.onErrorClear}>Clear</Button>
|
||||
</Alert>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{barContents}
|
||||
{errorAlert}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
551
static/ui.js
Normal file
551
static/ui.js
Normal file
@ -0,0 +1,551 @@
|
||||
// Import all the objects we want to use from ReactBootstrap
|
||||
var Jumbotron = ReactBootstrap.Jumbotron;
|
||||
var Panel = ReactBootstrap.Panel;
|
||||
var ButtonGroup = ReactBootstrap.ButtonGroup;
|
||||
|
||||
var NewUserForm = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {error: "",
|
||||
name: "",
|
||||
username: "",
|
||||
email: "",
|
||||
password: "",
|
||||
confirm_password: "",
|
||||
passwordChanged: false,
|
||||
initial_password: ""};
|
||||
},
|
||||
passwordValidationState: function() {
|
||||
if (this.state.passwordChanged) {
|
||||
if (this.state.password.length >= 10)
|
||||
return "success";
|
||||
else if (this.state.password.length >= 6)
|
||||
return "warning";
|
||||
else
|
||||
return "error";
|
||||
}
|
||||
},
|
||||
confirmPasswordValidationState: function() {
|
||||
if (this.state.confirm_password.length > 0) {
|
||||
if (this.state.confirm_password == this.state.password)
|
||||
return "success";
|
||||
else
|
||||
return "error";
|
||||
}
|
||||
},
|
||||
handleCancel: function() {
|
||||
if (this.props.onCancel != null)
|
||||
this.props.onCancel();
|
||||
},
|
||||
handleChange: function() {
|
||||
if (this.refs.password.getValue() != this.state.initial_password)
|
||||
this.setState({passwordChanged: true});
|
||||
this.setState({
|
||||
name: this.refs.name.getValue(),
|
||||
username: this.refs.username.getValue(),
|
||||
email: this.refs.email.getValue(),
|
||||
password: this.refs.password.getValue(),
|
||||
confirm_password: this.refs.confirm_password.getValue()
|
||||
});
|
||||
},
|
||||
handleSubmit: function(e) {
|
||||
var u = new User();
|
||||
var error = "";
|
||||
e.preventDefault();
|
||||
|
||||
u.Name = this.state.name;
|
||||
u.Username = this.state.username;
|
||||
u.Email = this.state.email;
|
||||
u.Password = this.state.password;
|
||||
if (u.Password != this.state.confirm_password) {
|
||||
this.setState({error: "Error: password do not match"});
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleCreateNewUser(u);
|
||||
},
|
||||
handleCreateNewUser: function(user) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
url: "user/",
|
||||
data: {user: user.toJSON()},
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
this.setState({error: e});
|
||||
} else {
|
||||
this.props.onNewUser();
|
||||
}
|
||||
}.bind(this),
|
||||
error: function(jqXHR, status, error) {
|
||||
var e = new Error();
|
||||
e.ErrorId = 5;
|
||||
e.ErrorString = "Request Failed: " + status + error;
|
||||
this.setState({error: e});
|
||||
}.bind(this),
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
var title = <h3>Create New User</h3>;
|
||||
return (
|
||||
<Panel header={title} bsStyle="info">
|
||||
<span color="red">{this.state.error}</span>
|
||||
<form onSubmit={this.handleSubmit}
|
||||
className="form-horizontal">
|
||||
<Input type="text"
|
||||
label="Name"
|
||||
value={this.state.name}
|
||||
onChange={this.handleChange}
|
||||
ref="name"
|
||||
labelClassName="col-xs-2"
|
||||
wrapperClassName="col-xs-10"/>
|
||||
<Input type="text"
|
||||
label="Username"
|
||||
value={this.state.username}
|
||||
onChange={this.handleChange}
|
||||
ref="username"
|
||||
labelClassName="col-xs-2"
|
||||
wrapperClassName="col-xs-10"/>
|
||||
<Input type="email"
|
||||
label="Email"
|
||||
value={this.state.email}
|
||||
onChange={this.handleChange}
|
||||
ref="email"
|
||||
labelClassName="col-xs-2"
|
||||
wrapperClassName="col-xs-10"/>
|
||||
<Input type="password"
|
||||
label="Password"
|
||||
value={this.state.password}
|
||||
onChange={this.handleChange}
|
||||
ref="password"
|
||||
labelClassName="col-xs-2"
|
||||
wrapperClassName="col-xs-10"
|
||||
bsStyle={this.passwordValidationState()}
|
||||
hasFeedback/>
|
||||
<Input type="password"
|
||||
label="Confirm Password"
|
||||
value={this.state.confirm_password}
|
||||
onChange={this.handleChange}
|
||||
ref="confirm_password"
|
||||
labelClassName="col-xs-2"
|
||||
wrapperClassName="col-xs-10"
|
||||
bsStyle={this.confirmPasswordValidationState()}
|
||||
hasFeedback/>
|
||||
<ButtonGroup className="pull-right">
|
||||
<Button onClick={this.handleCancel}
|
||||
bsStyle="warning">Cancel</Button>
|
||||
<Button type="submit"
|
||||
bsStyle="success">Create New User</Button>
|
||||
</ButtonGroup>
|
||||
</form>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var AccountSettings = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {error: "",
|
||||
name: this.props.user.Name,
|
||||
username: this.props.user.Username,
|
||||
email: this.props.user.Email,
|
||||
password: BogusPassword,
|
||||
confirm_password: BogusPassword,
|
||||
passwordChanged: false,
|
||||
initial_password: BogusPassword};
|
||||
},
|
||||
passwordValidationState: function() {
|
||||
if (this.state.passwordChanged) {
|
||||
if (this.state.password.length >= 10)
|
||||
return "success";
|
||||
else if (this.state.password.length >= 6)
|
||||
return "warning";
|
||||
else
|
||||
return "error";
|
||||
}
|
||||
},
|
||||
confirmPasswordValidationState: function() {
|
||||
if (this.state.confirm_password.length > 0) {
|
||||
if (this.state.confirm_password == this.state.password)
|
||||
return "success";
|
||||
else
|
||||
return "error";
|
||||
}
|
||||
},
|
||||
handleCancel: function() {
|
||||
if (this.props.onCancel != null)
|
||||
this.props.onCancel();
|
||||
},
|
||||
handleChange: function() {
|
||||
if (this.refs.password.getValue() != this.state.initial_password)
|
||||
this.setState({passwordChanged: true});
|
||||
this.setState({
|
||||
name: this.refs.name.getValue(),
|
||||
username: this.refs.username.getValue(),
|
||||
email: this.refs.email.getValue(),
|
||||
password: this.refs.password.getValue(),
|
||||
confirm_password: this.refs.confirm_password.getValue()
|
||||
});
|
||||
},
|
||||
handleSubmit: function(e) {
|
||||
var u = new User();
|
||||
var error = "";
|
||||
e.preventDefault();
|
||||
|
||||
u.UserId = this.props.user.UserId;
|
||||
u.Name = this.state.name;
|
||||
u.Username = this.state.username;
|
||||
u.Email = this.state.email;
|
||||
if (this.state.passwordChanged) {
|
||||
u.Password = this.state.password;
|
||||
if (u.Password != this.state.confirm_password) {
|
||||
this.setState({error: "Error: password do not match"});
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
u.Password = BogusPassword;
|
||||
}
|
||||
|
||||
this.handleSaveSettings(u);
|
||||
},
|
||||
handleSaveSettings: function(user) {
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
dataType: "json",
|
||||
url: "user/"+user.UserId+"/",
|
||||
data: {user: user.toJSON()},
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
this.setState({error: e});
|
||||
} else {
|
||||
user.Password = "";
|
||||
this.props.onSettingsSubmitted(user);
|
||||
}
|
||||
}.bind(this),
|
||||
error: function(jqXHR, status, error) {
|
||||
var e = new Error();
|
||||
e.ErrorId = 5;
|
||||
e.ErrorString = "Request Failed: " + status + error;
|
||||
this.setState({error: e});
|
||||
}.bind(this),
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
var title = <h3>Edit Account Settings</h3>;
|
||||
return (
|
||||
<Panel header={title} bsStyle="info">
|
||||
<span color="red">{this.state.error}</span>
|
||||
<form onSubmit={this.handleSubmit}
|
||||
className="form-horizontal">
|
||||
<Input type="text"
|
||||
label="Name"
|
||||
value={this.state.name}
|
||||
onChange={this.handleChange}
|
||||
ref="name"
|
||||
labelClassName="col-xs-2"
|
||||
wrapperClassName="col-xs-10"/>
|
||||
<Input type="text"
|
||||
label="Username"
|
||||
value={this.state.username}
|
||||
onChange={this.handleChange}
|
||||
ref="username"
|
||||
labelClassName="col-xs-2"
|
||||
wrapperClassName="col-xs-10"/>
|
||||
<Input type="email"
|
||||
label="Email"
|
||||
value={this.state.email}
|
||||
onChange={this.handleChange}
|
||||
ref="email"
|
||||
labelClassName="col-xs-2"
|
||||
wrapperClassName="col-xs-10"/>
|
||||
<Input type="password"
|
||||
label="Password"
|
||||
value={this.state.password}
|
||||
onChange={this.handleChange}
|
||||
ref="password"
|
||||
labelClassName="col-xs-2"
|
||||
wrapperClassName="col-xs-10"
|
||||
bsStyle={this.passwordValidationState()}
|
||||
hasFeedback/>
|
||||
<Input type="password"
|
||||
label="Confirm Password"
|
||||
value={this.state.confirm_password}
|
||||
onChange={this.handleChange}
|
||||
ref="confirm_password"
|
||||
labelClassName="col-xs-2"
|
||||
wrapperClassName="col-xs-10"
|
||||
bsStyle={this.confirmPasswordValidationState()}
|
||||
hasFeedback/>
|
||||
<ButtonGroup className="pull-right">
|
||||
<Button onClick={this.handleCancel}
|
||||
bsStyle="warning">Cancel</Button>
|
||||
<Button type="submit"
|
||||
bsStyle="success">Save Settings</Button>
|
||||
</ButtonGroup>
|
||||
</form>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var MoneyGoApp = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
hash: "home",
|
||||
session: new Session(),
|
||||
user: new User(),
|
||||
accounts: [],
|
||||
account_map: {},
|
||||
error: new Error()
|
||||
};
|
||||
},
|
||||
componentDidMount: function() {
|
||||
this.getSession();
|
||||
this.handleHashChange();
|
||||
if ("onhashchange" in window) {
|
||||
window.onhashchange = this.handleHashChange;
|
||||
}
|
||||
},
|
||||
handleHashChange: function() {
|
||||
var hash = location.hash.replace(/^#/, '');
|
||||
if (hash.length == 0)
|
||||
hash = "home";
|
||||
if (hash != this.state.hash)
|
||||
this.setHash(hash);
|
||||
},
|
||||
setHash: function(hash) {
|
||||
location.hash = hash;
|
||||
if (this.state.hash != hash)
|
||||
this.setState({hash: hash});
|
||||
},
|
||||
ajaxError: function(jqXHR, status, error) {
|
||||
var e = new Error();
|
||||
e.ErrorId = 5;
|
||||
e.ErrorString = "Request Failed: " + status + error;
|
||||
this.setState({error: e});
|
||||
},
|
||||
getSession: function() {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
url: "session/",
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
var s = new Session();
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
if (e.ErrorId != 1 /* Not Signed In*/)
|
||||
this.setState({error: e});
|
||||
} else {
|
||||
s.fromJSON(data);
|
||||
}
|
||||
this.setState({session: s});
|
||||
this.getUser();
|
||||
this.getAccounts();
|
||||
}.bind(this),
|
||||
error: this.ajaxError
|
||||
});
|
||||
},
|
||||
getUser: function() {
|
||||
if (!this.state.session.isSession())
|
||||
return;
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
url: "user/"+this.state.session.UserId+"/",
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
var u = new User();
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
this.setState({error: e});
|
||||
} else {
|
||||
u.fromJSON(data);
|
||||
}
|
||||
this.setState({user: u});
|
||||
}.bind(this),
|
||||
error: this.ajaxError
|
||||
});
|
||||
},
|
||||
getAccounts: function() {
|
||||
if (!this.state.session.isSession()) {
|
||||
this.setState({accounts: [], account_map: {}});
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
url: "account/",
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
var accounts = [];
|
||||
var account_map = {};
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
this.setState({error: e});
|
||||
} else {
|
||||
for (var i = 0; i < data.accounts.length; i++) {
|
||||
var a = new Account();
|
||||
a.fromJSON(data.accounts[i]);
|
||||
accounts.push(a);
|
||||
account_map[a.AccountId] = a;
|
||||
}
|
||||
//Populate Children arrays in account objects
|
||||
for (var i = 0; i < accounts.length; i++) {
|
||||
var a = accounts[i];
|
||||
if (!a.isRootAccount())
|
||||
account_map[a.ParentAccountId].Children.push(a);
|
||||
}
|
||||
}
|
||||
this.setState({accounts: accounts, account_map: account_map});
|
||||
}.bind(this),
|
||||
error: this.ajaxError
|
||||
});
|
||||
},
|
||||
handleErrorClear: function() {
|
||||
this.setState({error: new Error()});
|
||||
},
|
||||
handleLoginSubmit: function(user) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
url: "session/",
|
||||
data: {user: user.toJSON()},
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
this.setState({error: e});
|
||||
} else {
|
||||
this.getSession();
|
||||
this.setHash("home");
|
||||
}
|
||||
}.bind(this),
|
||||
error: this.ajaxError
|
||||
});
|
||||
},
|
||||
handleLogoutSubmit: function() {
|
||||
this.setState({accounts: [], account_map: {}});
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
dataType: "json",
|
||||
url: "session/",
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
this.setState({error: e});
|
||||
}
|
||||
this.setState({session: new Session(), user: new User()});
|
||||
}.bind(this),
|
||||
error: this.ajaxError
|
||||
});
|
||||
},
|
||||
handleAccountSettings: function() {
|
||||
this.setHash("account");
|
||||
},
|
||||
handleSettingsSubmitted: function(user) {
|
||||
this.setState({user: user});
|
||||
this.setHash("home");
|
||||
},
|
||||
handleCreateNewUser: function() {
|
||||
this.setHash("new_user");
|
||||
},
|
||||
handleGoHome: function(user) {
|
||||
this.setHash("home");
|
||||
},
|
||||
handleCreateAccount: function(account) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
url: "account/",
|
||||
data: {account: account.toJSON()},
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
this.setState({error: e});
|
||||
} else {
|
||||
this.getAccounts();
|
||||
}
|
||||
}.bind(this),
|
||||
error: this.ajaxError
|
||||
});
|
||||
},
|
||||
handleUpdateAccount: function(account) {
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
dataType: "json",
|
||||
url: "account/"+account.AccountId+"/",
|
||||
data: {account: account.toJSON()},
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
this.setState({error: e});
|
||||
} else {
|
||||
this.getAccounts();
|
||||
}
|
||||
}.bind(this),
|
||||
error: this.ajaxError
|
||||
});
|
||||
},
|
||||
handleDeleteAccount: function(account) {
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
dataType: "json",
|
||||
url: "account/"+account.AccountId+"/",
|
||||
success: function(data, status, jqXHR) {
|
||||
var e = new Error();
|
||||
e.fromJSON(data);
|
||||
if (e.isError()) {
|
||||
this.setState({error: e});
|
||||
} else {
|
||||
this.getAccounts();
|
||||
}
|
||||
}.bind(this),
|
||||
error: this.ajaxError
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
var mainContent;
|
||||
if (this.state.hash == "new_user") {
|
||||
mainContent = <NewUserForm onNewUser={this.handleGoHome} onCancel={this.handleGoHome}/>
|
||||
} else if (this.state.hash == "account" && this.state.user.isUser()) {
|
||||
mainContent = <AccountSettings user={this.state.user} onSettingsSubmitted={this.handleSettingsSubmitted} onCancel={this.handleGoHome}/>
|
||||
} else {
|
||||
if (this.state.user.isUser())
|
||||
mainContent = <AccountList
|
||||
accounts={this.state.accounts}
|
||||
account_map={this.state.account_map}
|
||||
onCreateAccount={this.handleCreateAccount}
|
||||
onUpdateAccount={this.handleUpdateAccount}
|
||||
onDeleteAccount={this.handleDeleteAccount} />
|
||||
else
|
||||
mainContent =
|
||||
<Jumbotron>
|
||||
<h1>Money<i>Go</i></h1>
|
||||
<p><i>Go</i> manage your money.</p>
|
||||
</Jumbotron>
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TopBar
|
||||
error={this.state.error}
|
||||
onErrorClear={this.handleErrorClear}
|
||||
onLoginSubmit={this.handleLoginSubmit}
|
||||
onCreateNewUser={this.handleCreateNewUser}
|
||||
user={this.state.user}
|
||||
onAccountSettings={this.handleAccountSettings}
|
||||
onLogoutSubmit={this.handleLogoutSubmit} />
|
||||
{mainContent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
React.render(<MoneyGoApp />, document.getElementById("content"));
|
Loading…
Reference in New Issue
Block a user