From 09d5e12a541119ee07ce94f46ddf034b31ae7700 Mon Sep 17 00:00:00 2001 From: Sidhin S Thomas Date: Sun, 28 Jul 2024 13:21:52 +0530 Subject: [PATCH] Connect backend for MVP --- .env.production | 2 +- api/budget_controller.cs | 6 +++--- api/models/budget.cs | 2 +- api/models/category.cs | 2 +- api/models/expense.cs | 2 +- api/models/recurring.cs | 6 +++--- api/models/user_action.cs | 2 +- api/services/db_service.cs | 21 +++++++++++++++++---- api/services/user_data_service.cs | 10 +++++++--- ui/services/data_service.ts | 16 +++++++++++++--- 10 files changed, 48 insertions(+), 21 deletions(-) diff --git a/.env.production b/.env.production index e05aed1..72da694 100644 --- a/.env.production +++ b/.env.production @@ -1,3 +1,3 @@ VITE_CREATE_DUMMY_DATA=false VITE_PING_REMOTE=false -VITE_USE_LOCAL_DATA_SERVICE=true \ No newline at end of file +VITE_USE_LOCAL_DATA_SERVICE=false \ No newline at end of file diff --git a/api/budget_controller.cs b/api/budget_controller.cs index 16598fb..d85429f 100644 --- a/api/budget_controller.cs +++ b/api/budget_controller.cs @@ -28,10 +28,10 @@ public async Task CreateBudget([FromBody] CreateBudgetInput input return Ok(await _userDataService.CreateBudget(input.name)); } - [HttpPost("{budget_id}/category")] - public async Task AddCategoryInput(string budget_id, Category category) + [HttpPost("{budget_id}/categories")] + public async Task AddCategoryInput(string budget_id, List categoryList) { - return Ok(await _userDataService.AddCategoryToBudget(budget_id, category)); + return Ok(await _userDataService.AddCategoryToBudget(budget_id, categoryList)); } diff --git a/api/models/budget.cs b/api/models/budget.cs index 03e8661..9996741 100644 --- a/api/models/budget.cs +++ b/api/models/budget.cs @@ -11,6 +11,6 @@ public class Budget public required List unplannedList { get; set; } public required TimeUnit period { get; set; } public required List userActions { get; set; } - public DateTime last_updated { get; set; } + public long last_updated { get; set; } public required List authorized_users { get; set; } } \ No newline at end of file diff --git a/api/models/category.cs b/api/models/category.cs index 259a3bf..d4b8599 100644 --- a/api/models/category.cs +++ b/api/models/category.cs @@ -7,7 +7,7 @@ public class Category public required string Description { get; set; } public decimal Allocation { get; set; } public bool IsActive { get; set; } - public DateTime LastUpdated { get; set; } + public long LastUpdated { get; set; } public required string Currency { get; set; } public required List ExpenseList { get; set; } } diff --git a/api/models/expense.cs b/api/models/expense.cs index 9cd2813..4d88b74 100644 --- a/api/models/expense.cs +++ b/api/models/expense.cs @@ -6,5 +6,5 @@ public class Expense public required string Title { get; set; } public decimal Amount { get; set; } public int CategoryId { get; set; } - public DateTime Timestamp { get; set; } + public long Timestamp { get; set; } } \ No newline at end of file diff --git a/api/models/recurring.cs b/api/models/recurring.cs index 320536f..2dafd40 100644 --- a/api/models/recurring.cs +++ b/api/models/recurring.cs @@ -18,10 +18,10 @@ public class Recurring public required string Name { get; set; } public required string Description { get; set; } public bool IsActive { get; set; } - public DateTime LastUpdated { get; set; } + public long LastUpdated { get; set; } public RecurringType Frequency { get; set; } public int FrequencyUnit { get; set; } // This has different meanings based on the frequency, if monthly, it will be day of month, if weekly, it will be day of week etc. - public DateTime StartDate { get; set; } - public DateTime EndDate { get; set; } + public long StartDate { get; set; } + public long EndDate { get; set; } public decimal Amount { get; set; } } \ No newline at end of file diff --git a/api/models/user_action.cs b/api/models/user_action.cs index 186697e..d1bc52e 100644 --- a/api/models/user_action.cs +++ b/api/models/user_action.cs @@ -17,7 +17,7 @@ public enum UserActionType public class UserAction { - public DateTime timestamp { get; set; } + public long timestamp { get; set; } public UserActionType type { get; set; } public Category? category { get; set; } public Expense? expense { get; set; } diff --git a/api/services/db_service.cs b/api/services/db_service.cs index d5324e9..e76273f 100644 --- a/api/services/db_service.cs +++ b/api/services/db_service.cs @@ -40,6 +40,11 @@ public async Task GetUserData(string user_id) } } + public async Task UpdateUserData(UserData userData) + { + await _container.UpsertItemAsync(userData, new PartitionKey(userData.id)); + } + public async Task GetBudgetAsync(string budget_id) { return await _container.ReadItemAsync(budget_id, new PartitionKey(budget_id)); @@ -66,7 +71,7 @@ public async Task CreateNewBudgetAsync(string name) authorized_users = new List() { _identityService.GetUserIdentity() }, categoryList = new List(), history_id = history.id, - last_updated = DateTime.Now, + last_updated = DateTime.UtcNow.Ticks, period = period, recurringList = new List(), unplannedList = new List(), @@ -82,6 +87,7 @@ public async Task CreateNewBudgetAsync(string name) public async Task UpdateBudgetAsync(Budget budget) { + budget.last_updated = DateTime.UtcNow.Ticks; await _container.UpsertItemAsync(budget, new PartitionKey(budget.id)); } @@ -90,15 +96,19 @@ public async Task AddExpenseAsync(string budget_id, Expense expense) Budget budget = await GetBudgetAsync(budget_id); Category cat = budget.categoryList?.Find(c => c.Id == expense.CategoryId) ?? throw new Exception("Category not found"); expense.Id = cat.ExpenseList.LastOrDefault()?.Id ?? 0; + expense.Timestamp = DateTime.UtcNow.Ticks; cat.ExpenseList.Add(expense); + cat.LastUpdated = DateTime.UtcNow.Ticks; await UpdateBudgetAsync(budget); } public async Task UpdateExpenseAsync(string budget_id, Expense expense) { Budget budget = await GetBudgetAsync(budget_id); + expense.Timestamp = DateTime.UtcNow.Ticks; Category category = budget.categoryList?.Find(c => c.Id == expense.CategoryId) ?? throw new Exception("Category not found"); category.ExpenseList[category.ExpenseList.FindIndex(e => e.Id == expense.Id)] = expense; + category.LastUpdated = DateTime.UtcNow.Ticks; await UpdateBudgetAsync(budget); } @@ -107,14 +117,16 @@ public async Task DeleteExpense(string budget_id, Expense expense) Budget budget = await GetBudgetAsync(budget_id); Category category = budget.categoryList?.Find(c => c.Id == expense.CategoryId) ?? throw new Exception("Category not found"); category.ExpenseList.RemoveAll(e => e.Id == expense.Id); + category.LastUpdated = DateTime.UtcNow.Ticks; await UpdateBudgetAsync(budget); } - public async Task AddCategoryAsync(string budget_id, Category category) + public async Task AddCategoryAsync(string budget_id, List categoryList) { Budget budget = await GetBudgetAsync(budget_id); - category.Id = (budget.categoryList.LastOrDefault()?.Id ?? 0) + 1; - budget.categoryList.Add(category); + int last_id = (budget.categoryList.LastOrDefault()?.Id ?? 0) + 1; + categoryList.ForEach(c => { c.Id = last_id++; c.LastUpdated = DateTime.UtcNow.Ticks; }); + budget.categoryList.AddRange(categoryList); await UpdateBudgetAsync(budget); } @@ -122,6 +134,7 @@ public async Task UpdateCategoryAsync(string budget_id, Category category) { Budget budget = await GetBudgetAsync(budget_id); budget.categoryList[budget.categoryList.FindIndex(c => c.Id == category.Id)] = category; + category.LastUpdated = DateTime.UtcNow.Ticks; await UpdateBudgetAsync(budget); } diff --git a/api/services/user_data_service.cs b/api/services/user_data_service.cs index 3a30f0a..8523986 100644 --- a/api/services/user_data_service.cs +++ b/api/services/user_data_service.cs @@ -28,7 +28,11 @@ public async Task> FetchAssociatedBudgets() public async Task CreateBudget(string name) { - return await _dbService.CreateNewBudgetAsync(name); + var budget = await _dbService.CreateNewBudgetAsync(name); + var user_data = await _dbService.GetUserData(_identityService.GetUserIdentity()); + user_data.BudgetIds.Add(budget.id); + await _dbService.UpdateUserData(user_data); + return budget; } public async Task AddExpenseToBudget(string budget_id, Expense expense) @@ -37,9 +41,9 @@ public async Task AddExpenseToBudget(string budget_id, Expense expense) return await _dbService.GetBudgetAsync(budget_id); } - public async Task AddCategoryToBudget(string budget_id, Category category) + public async Task AddCategoryToBudget(string budget_id, List categoryList) { - await _dbService.AddCategoryAsync(budget_id, category); + await _dbService.AddCategoryAsync(budget_id, categoryList); return await _dbService.GetBudgetAsync(budget_id); } } \ No newline at end of file diff --git a/ui/services/data_service.ts b/ui/services/data_service.ts index bc2c2bb..048fe09 100644 --- a/ui/services/data_service.ts +++ b/ui/services/data_service.ts @@ -30,7 +30,8 @@ class RemoteDataService implements DataService { BASE_URL: string; constructor() { - this.BASE_URL = window.location.hostname; + this.BASE_URL = ""; + console.log(`Using remote data service at ${this.BASE_URL}`); } createBudget(name: string): Promise { @@ -43,6 +44,7 @@ class RemoteDataService implements DataService { }, }).then((response) => response.json() as Promise); } + getBudget(): Promise { const endpoint: string = `${this.BASE_URL}/api/Budget`; return fetch(endpoint, { method: 'GET' }).then((response) => response.json() as Promise); @@ -51,6 +53,7 @@ class RemoteDataService implements DataService { getHistory(): Promise { throw new Error("Not implemented"); } + updateCategory(budger_id: string, category: Category): Promise { const endpoint: string = `${this.BASE_URL}/api/Budget/${budger_id}`; return fetch(endpoint, { @@ -73,8 +76,15 @@ class RemoteDataService implements DataService { }).then((response) => response.json() as Promise); } - updateExpense(_budget_id: string, _expense: Expense): Promise { - throw new Error("Not implemented"); + updateExpense(_budget_id: string, expense: Expense): Promise { + const endpoint: string = `${this.BASE_URL}/api/Budget/${_budget_id}/expense`; + return fetch(endpoint, { + method: 'POST', + body: JSON.stringify(expense), + headers: { + 'Content-Type': 'application/json' + }, + }).then((response) => response.json() as Promise); } deleteExpense(_budget_id: string, _expenseId: number): Promise {