Account.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import EncryptionHandler from "../EncryptionHandler.js";
  2. import Notifier from "../Notifier.js";
  3. import Format from "../Format.js";
  4. import Transaction from "./Transaction.js";
  5. import Income from "./Income.js";
  6. import Bill from "./Bill.js";
  7. import Allowance from "./Allowance.js";
  8. export default class Account{
  9. constructor(id, iv, data){
  10. this._id = id;
  11. this._iv = iv;
  12. this._name = data.name;
  13. this._balance = data.balance;
  14. this._income = data.income.map(Income.fromObject);
  15. this._bills = data.bills.map(Bill.fromObject);
  16. this._allowances = data.allowances.map(Allowance.fromObject);
  17. this._transactions = [];
  18. this._populated = false;
  19. }
  20. get id(){
  21. return this._id;
  22. }
  23. get name(){
  24. return this._name;
  25. }
  26. get balance(){
  27. return Format.centsToDollars(this._balance);
  28. }
  29. get transactions(){
  30. return this._transactions;
  31. }
  32. get income(){
  33. return this._income;
  34. }
  35. get isPopulated(){
  36. return this._populated;
  37. }
  38. set isPopulated(v){
  39. if(typeof v === "boolean") this._populated = v;
  40. }
  41. getCategory(category, categoryId){
  42. if(category === "discretionary") return {name: "Discretionary"};
  43. let list;
  44. switch(category){
  45. case "income": list = this._income; break;
  46. case "bill": list = this._bills; break;
  47. case "allowance": list = this._allowances; break;
  48. }
  49. for(let i = 0; i < list.length; i++){
  50. if(list[i].id === categoryId) return list[i];
  51. }
  52. }
  53. categorySpent(category){
  54. let total = 0;
  55. for(let i = 0; i < this._transactions.length; i++){
  56. if(this._transactions[i].categoryId === category.id){
  57. total += this._transactions[i].rawAmount;
  58. }
  59. }
  60. return Format.centsToDollars(total);
  61. }
  62. incomeTotal(){
  63. let income = 0;
  64. for(let i = 0; i < this._income.length; i++){
  65. income += this._income[i].amount;
  66. }
  67. return Format.centsToDollars(income);
  68. }
  69. billsTotal(){
  70. let bills = 0;
  71. for(let i = 0; i < this._bills.length; i++){
  72. bills += this._bills[i].amount;
  73. }
  74. return Format.centsToDollars(bills);
  75. }
  76. static async create(name, balance){
  77. const data = {
  78. name: name,
  79. balance: Format.dollarsToCents(balance),
  80. income: [],
  81. bills: [],
  82. allowances: []
  83. };
  84. const iv = encryptionHandler.generateIv();
  85. const encryptedData = await encryptionHandler.encrypt(data, iv);
  86. let response;
  87. try{
  88. response = await fetch("/api/account", {
  89. method: "POST",
  90. headers: {"Content-Type": "application/json"},
  91. body: JSON.stringify({data: encryptedData, iv})
  92. });
  93. }catch(e){
  94. new Notifier("error", "Something went wrong, try refreshing the page");
  95. }
  96. if(response.error) new Notifier("error", response.error.message);
  97. return new Account(response.id, iv, data);
  98. }
  99. async addIncome(name, amount){
  100. this._income.push(Income.create(name, Format.dollarsToCents(amount)));
  101. await this.save();
  102. }
  103. async addBill(name, amount){
  104. this._bills.push(Bill.create(name, Format.dollarsToCents(amount)));
  105. await this.save();
  106. }
  107. async addAllowance(name, amount, isPercent){
  108. if(isPercent){
  109. amount = Number(amount);
  110. }else{
  111. amount = Format.dollarsToCents(amount);
  112. }
  113. this._allowances.push(Allowance.create(name, amount, isPercent));
  114. await this.save();
  115. }
  116. addTransaction(transaction){
  117. this._transactions.push(transaction);
  118. this.sortTransactions();
  119. }
  120. addManyTransactions(transactions){
  121. this._transactions.push(...transactions);
  122. this.sortTransactions();
  123. }
  124. removeTransaction(transaction){
  125. if(transaction instanceof Transaction){
  126. for(let i = 0; i < this._transactions.length; i++){
  127. if(this._transactions[i] === transaction){
  128. this._transactions.splice(i, 1);
  129. break;
  130. }
  131. }
  132. }
  133. }
  134. sortTransactions(){
  135. this._transactions.sort((a, b)=>{a > b ? 1 : -1});
  136. }
  137. listIncome(){
  138. const income = [];
  139. for(let i = 0; i < this._income.length; i++){
  140. income.push({
  141. id: this._income[i].id,
  142. name: this._income[i].name
  143. });
  144. }
  145. return income;
  146. }
  147. listBills(){
  148. const bills = [];
  149. for(let i = 0; i < this._bills.length; i++){
  150. bills.push({
  151. id: this._bills[i].id,
  152. name: this._bills[i].name
  153. });
  154. }
  155. return bills;
  156. }
  157. listAllowances(){
  158. const allowances = [];
  159. for(let i = 0; i < this._allowances.length; i++){
  160. allowances.push({
  161. id: this._allowances[i].id,
  162. name: this._allowances[i].name
  163. });
  164. }
  165. return allowances;
  166. }
  167. async populateTransactions(){
  168. if(this._populated) return;
  169. let from = new Date();
  170. from.setDate(1);
  171. const to = new Date();
  172. let response;
  173. try{
  174. response = await fetch("/api/transaction/search", {
  175. method: "POST",
  176. headers: {"Content-Type": "application/json"},
  177. body: JSON.stringify({
  178. account: this._id,
  179. from: Format.transactionDate(from),
  180. to: Format.transactionDate(to)
  181. })
  182. });
  183. }catch(e){
  184. new Notifier("error", "Something went wrong, try refreshing the page");
  185. }
  186. if(response.error){
  187. new Notifier("error", response.error.message);
  188. }else{
  189. for(let i = 0; i < response.length; i++){
  190. this._transactions = Transaction.decrypt(response[i]);
  191. }
  192. this._populated = true;
  193. }
  194. }
  195. async save(){
  196. const data = {
  197. name: this._name,
  198. balance: this._balance,
  199. income: this._income.map(i => i.serialize()),
  200. bills: this._bills.map(b => b.serialize()),
  201. allowances: this._allowances.map(a => a.serialize())
  202. };
  203. const encryptedData = await encryptionHandler.encrypt(data, this._iv);
  204. let response;
  205. try{
  206. response = await fetch("/api/account", {
  207. method: "PUT",
  208. headers: {"Content-Type": "application/json"},
  209. body: JSON.stringify({
  210. id: this._id,
  211. data: encryptedData
  212. })
  213. });
  214. }catch(e){
  215. new Notifier("error", "Something went wrong, try refreshing the page");
  216. }
  217. if(response.error) new Notifier("error", response.error.message);
  218. }
  219. }