Skip to content

Commit

Permalink
Merge pull request #2 from ParadoxZero/sidhin/edit_categories_page
Browse files Browse the repository at this point in the history
Implement edit categories page
  • Loading branch information
ParadoxZero authored Aug 4, 2024
2 parents c7eebc6 + ee125e0 commit cc63bb6
Show file tree
Hide file tree
Showing 15 changed files with 523 additions and 188 deletions.
2 changes: 1 addition & 1 deletion .env.development
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VITE_CREATE_DUMMY_DATA=false
VITE_CREATE_DUMMY_DATA=true
VITE_PING_REMOTE=false
VITE_USE_LOCAL_DATA_SERVICE=true
VITE_CLEAR_USER_DATA_ON_LOAD=true
21 changes: 20 additions & 1 deletion api/budget_controller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,31 @@ public async Task<IActionResult> CreateBudget([FromBody] CreateBudgetInput input
return Ok(await _userDataService.CreateBudget(input.name));
}

[HttpPost("{budget_id}/categories")]
[HttpDelete("{budget_id}")]
public async Task<IActionResult> DeleteBudget(string budget_id)
{
await _userDataService.DeleteBudget(budget_id);
return Ok();
}

[HttpPost("{budget_id}/add_categories")]
public async Task<IActionResult> AddCategoryInput(string budget_id, List<Category> categoryList)
{
return Ok(await _userDataService.AddCategoryToBudget(budget_id, categoryList));
}

[HttpPost("{budget_id}/update_category")]
public async Task<IActionResult> UpdateCategoryInput(string budget_id, Category category)
{
return Ok(await _userDataService.UpdateCategory(budget_id, category));
}

[HttpDelete("{budget_id}/category/{category_id}")]
public async Task<IActionResult> DeleteCategory(string budget_id, int category_id)
{
return Ok(await _userDataService.DeleteCategory(budget_id, category_id));
}


[HttpPost("{budget_id}/expense")]
public async Task<IActionResult> AddExpenseInput(string budget_id, Expense expense)
Expand Down
27 changes: 25 additions & 2 deletions api/services/db_service.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,16 @@ public async Task AddCategoryAsync(string budget_id, List<Category> categoryList
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;
foreach (Category cat in budget.categoryList)
{
if (cat.Id == category.Id)
{
cat.Name = category.Name;
cat.Allocation = category.Allocation;
cat.LastUpdated = DateTime.UtcNow.Ticks;
break;
}
}
await UpdateBudgetAsync(budget);
}

Expand All @@ -152,5 +160,20 @@ public async Task AddRecurringAsync(string budget_id, Recurring recurring)
await UpdateBudgetAsync(budget);
}

public async Task DeleteBudgetAsync(string budget_id)
{
var user_data = await GetUserData(_identityService.GetUserIdentity());
user_data.BudgetIds.Remove(budget_id);
await UpdateUserData(user_data);
await _container.DeleteItemAsync<Budget>(budget_id, new PartitionKey(budget_id));
}

public async Task<Budget> DeleteCategoryAsync(string budget_id, int category_id)
{
Budget budget = await GetBudgetAsync(budget_id);
budget.categoryList.RemoveAll(c => c.Id == category_id);
await UpdateBudgetAsync(budget);
return budget;
}
}
}
16 changes: 16 additions & 0 deletions api/services/user_data_service.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,20 @@ public async Task<Budget> AddCategoryToBudget(string budget_id, List<Category> c
await _dbService.AddCategoryAsync(budget_id, categoryList);
return await _dbService.GetBudgetAsync(budget_id);
}

public async Task<Budget> UpdateCategory(string budget_id, Category category)
{
await _dbService.UpdateCategoryAsync(budget_id, category);
return await _dbService.GetBudgetAsync(budget_id);
}

public async Task DeleteBudget(string budget_id)
{
await _dbService.DeleteBudgetAsync(budget_id);
}

public async Task<Budget> DeleteCategory(string budget_id, int category_id)
{
return await _dbService.DeleteCategoryAsync(budget_id, category_id);
}
}
16 changes: 13 additions & 3 deletions ui/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { navigation, store, View } from './store'
import { CreateDummyData } from './utils';
import { PingRemote } from './services/ping_service';
import NoBudgetAvailablePage from './pages/no-budget_page';
import CreateNewBudgetPage from './pages/create_new_budget_page';
import { ReactNode } from 'react';
import React from 'react';
import { connect } from 'react-redux';
import { ConfigProvider, Layout } from 'antd';
import Header from './components/header';
import Overview from './pages/overview';
import EditCategoriesPage from './pages/edit_categories_page';
import { Budget } from './datamodel/datamodel';


interface PreRun {
Expand All @@ -19,6 +21,7 @@ interface PreRun {
export interface AppProps {
view: View;
is_header_visible: boolean;
current_budget: Budget | null;
}

class App extends React.Component<AppProps> {
Expand Down Expand Up @@ -56,10 +59,10 @@ class App extends React.Component<AppProps> {
view: View.Overview,
is_header_visible: true
}
this.run_pre_run();
}

componentDidMount(): void {
this.run_pre_run();
}

render(): ReactNode {
Expand Down Expand Up @@ -91,16 +94,23 @@ class App extends React.Component<AppProps> {
case View.Overview:
return <Overview />
case View.NoBudgetAvailable:
return <NoBudgetAvailablePage />
return <CreateNewBudgetPage />
case View.CategoryEdit:
return <EditCategoriesPage budget={this.props.current_budget!} />
default:
return (<>Not Found</>)
}
}
}
function mapStateToProps(state: any): AppProps {
let budget = null;
if (state.budget.budget_list && state.budget.selected_budget_index !== null && state.budget.budget_list.length > state.budget.selected_budget_index) {
budget = state.budget.budget_list[state.budget.selected_budget_index];
}
return {
view: state.navigation.current_view,
is_header_visible: state.header.is_visible,
current_budget: budget
}
}

Expand Down
94 changes: 94 additions & 0 deletions ui/components/add_categories_form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { Button, Card, Empty, Form, FormInstance, Input, InputNumber } from "antd";
import React from "react";
import { Budget, Category, DataModelFactory } from "../datamodel/datamodel";
import { navigation, store, View } from "../store";
import { CloseOutlined } from "@ant-design/icons";
import { DataService, getDataService } from "../services/data_service";


export interface EditCategoriesFormProps {
budget_id: string;
categories?: Category[];
onCategoriesAdded: () => void;
onCancel: () => void;
}

interface EditCategoriesFormState {

}

export class AddCategoriesForm extends React.Component<EditCategoriesFormProps, EditCategoriesFormState> {
data_service: DataService;

constructor(props: EditCategoriesFormProps) {
super(props);
this.data_service = getDataService();
}

render() {
return (
this.render_add_category()
);
}

render_add_category() {
const formRef = React.createRef<FormInstance>();
const onFinish = (values: any) => {
const category_list: Category[] = [];
for (const raw_category of values.categories) {
const category = DataModelFactory.createCategory(0);
category.name = raw_category.name;
category.allocation = raw_category.allocation;
category_list.push(category);
}
this.setState({ is_loading: true });
this.data_service.createCategories(this.props.budget_id, category_list).then((value: Budget) => {
this.props.onCategoriesAdded();
}).catch((_error: any) => {
});
};
return (
<Form
name="add_categories"
style={{ maxWidth: 600 }}
autoComplete="off"
initialValues={{ categories: [] }}
ref={formRef}
onFinish={onFinish}
>
<Form.List name="categories">
{(fields, { add, remove }) => (
<div style={{ display: 'flex', rowGap: 16, flexDirection: 'column', justifyContent: 'center' }}>
{fields.map((field) => (
<Card
size="small"
key={field.key}
actions={[<CloseOutlined onClick={() => remove(field.name)} />]}
>
<Form.Item label="Name" name={[field.name, 'name']} rules={[{ required: true, message: "Name is required" }]}>
<Input />
</Form.Item>
<Form.Item label="Allocated Amount" name={[field.name, 'allocation']} rules={[{ required: true, message: "Allocation is required" }]}>
<InputNumber type="number" inputMode="numeric" />
</Form.Item>
</Card>
))}
{fields.length === 0 && (
<Empty description="No Categories Added" />
)}

<Button type="dashed" onClick={() => add()} block>
+ Add Category
</Button>

<Button type="primary" htmlType="submit" block>
Finalize
</Button>
<Button type="link" onClick={() => this.props.onCancel()}>Cancel</Button>
</div>
)}
</Form.List>
</Form>
);
}
}
Loading

0 comments on commit cc63bb6

Please sign in to comment.