Skip to content

Commit

Permalink
Fix date type issue - Add quickstart script - Update Readme
Browse files Browse the repository at this point in the history
  • Loading branch information
jordojordo committed Jul 24, 2024
1 parent ff716db commit 595ae7f
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 16 deletions.
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.git*
.git*
assets/frontend-demo.png
scripts
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,28 @@

## Overview

Horus Holdings is a cash flow management tool that allows users to input incomes and expenses and visualize their cash flow over time. The application includes user authentication to ensure that each user's data is secure and private.
Horus Holdings is a sophisticated cash flow management tool designed to help users track their incomes and expenses, providing a clear visualization of their cash flow over time.

Named after the Egyptian god Horus, who symbolizes protection, stability, and prosperity, this application aims to bring financial clarity and control to its users. By offering robust user authentication, Horus Holdings ensures that each user's financial data remains secure and private, echoing the protective nature of its namesake.

![Frontend Demo](assets/frontend-demo.png)

## Quickstart

To quickly get started with Horus Holdings using Docker, you can use the provided `quickstart.sh` script. This script will set up and run both the MySQL database and the Horus Holdings application in Docker containers.

```bash
./scripts/quickstart.sh
```

This script will:
- Pull the latest MySQL and Horus Holdings Docker images.
- Run the MySQL container with the specified environment variables.
- Wait for MySQL to initialize.
- Run the Horus Holdings container with the necessary environment variables.
- Output the URLs where the frontend and backend are accessible.

## Folder Structure

The application consists of a frontend and a backend:
- **Frontend**: Located in the `./src` directory.
Expand Down
Binary file added assets/frontend-demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions scripts/quickstart.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash

# Set environment variables
MYSQL_ROOT_PASSWORD=admin
MYSQL_DATABASE=devdb
DATABASE_URL="mysql://root:$MYSQL_ROOT_PASSWORD@localhost:3306/$MYSQL_DATABASE"
CORS_ORIGIN="http://localhost:3000"
JWT_SECRET="super-secret"

# Pull the latest MySQL and Horus Holdings images
echo "Pulling the latest MySQL and Horus Holdings Docker images..."
docker pull mysql:latest
docker pull ghcr.io/jordojordo/horus-holdings:latest

# Run the MySQL container
echo "Running the MySQL container..."
docker run -d --name mysql-dev \
-e MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD \
-e MYSQL_DATABASE=$MYSQL_DATABASE \
--network host \
mysql:latest

# Wait for MySQL to initialize
echo "Waiting for MySQL to initialize..."
until docker exec mysql-dev mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "USE $MYSQL_DATABASE;" 2> /dev/null; do
echo "Waiting for MySQL to be ready..."
sleep 2
done

# Run the Horus Holdings container
echo "Running the Horus Holdings container..."
docker run -d --name horus \
--network host \
-e DATABASE_URL=$DATABASE_URL \
-e CORS_ORIGIN=$CORS_ORIGIN \
-e JWT_SECRET=$JWT_SECRET \
ghcr.io/jordojordo/horus-holdings:latest

echo "Horus Holdings is now running!"
echo "Frontend is accessible at $CORS_ORIGIN"
echo "Backend is accessible at http://localhost:5000"
33 changes: 26 additions & 7 deletions src/components/FinancialForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ import axios from 'axios';
import {
Modal, Checkbox, Form, Input, InputNumber, DatePicker, Select, Space, message
} from 'antd';
import dayjs from 'dayjs';

import type { DatePickerProps } from 'antd';
import type { Dayjs } from 'dayjs';
import type { Item } from './ItemTable';

import useAuth from '../hooks/useAuth';
import { useTheme, THEME } from '../context/ThemeContext';
import type { Item } from './ItemTable';
import { Expense } from '../types/Expense';
import { Income } from '../types/Income';

Expand Down Expand Up @@ -34,10 +38,10 @@ const FinancialForm: React.FC<FinancialFormProps> = ({
const [id, setId] = useState(0);
const [description, setDescription] = useState('');
const [amount, setAmount] = useState<number>(0);
const [date, setDate] = useState<string | null>(null);
const [date, setDate] = useState<Dayjs | null | undefined>(null);
const [recurring, setRecurring] = useState(false);
const [recurrenceType, setRecurrenceType] = useState<string | null>(null);
const [recurrenceEndDate, setRecurrenceEndDate] = useState<string | null>(null);
const [recurrenceEndDate, setRecurrenceEndDate] = useState<Dayjs | null | undefined>(null);
const [category, setCategory] = useState<string | null | undefined>(undefined);

const colors = {
Expand Down Expand Up @@ -69,13 +73,16 @@ const FinancialForm: React.FC<FinancialFormProps> = ({

useEffect(() => {
if ( itemToUpdate ) {
const itemDate = dayjs(itemToUpdate.date);
const itemRecurrenceEndDate = dayjs(itemToUpdate.recurrenceEndDate);

setId(itemToUpdate.id);
setDescription(itemToUpdate.description);
setAmount(itemToUpdate.amount);
setDate(itemToUpdate.date);
setDate(itemDate.isValid() ? itemDate : null);
setRecurring(itemToUpdate.recurring);
setRecurrenceType(itemToUpdate.recurrenceType);
setRecurrenceEndDate(itemToUpdate.recurrenceEndDate);
setRecurrenceEndDate(itemRecurrenceEndDate.isValid() ? itemRecurrenceEndDate : null);

if ( itemToUpdate.category ) {
setCategory(itemToUpdate.category);
Expand Down Expand Up @@ -147,6 +154,18 @@ const FinancialForm: React.FC<FinancialFormProps> = ({
}
};

const handleDateChange: DatePickerProps['onChange'] = (date) => {
if ( date ) {
setDate(date);
}
};

const handleRecurrenceEndDateChange: DatePickerProps['onChange'] = (date) => {
if ( date ) {
setRecurrenceEndDate(date);
}
};

return (
<>
{!itemToUpdate && (
Expand Down Expand Up @@ -201,7 +220,7 @@ const FinancialForm: React.FC<FinancialFormProps> = ({
<InputNumber type="number" onChange={(e) => setAmount(e as number)} />
</Form.Item>
<Form.Item name="date" label="Date">
<DatePicker value={date} />
<DatePicker value={date} onChange={handleDateChange} />
</Form.Item>
{formType === 'expense' && (
<Form.Item name="category" label="Category" rules={[{ message: 'Please enter a category' }]}>
Expand All @@ -226,7 +245,7 @@ const FinancialForm: React.FC<FinancialFormProps> = ({
</Select>
</Form.Item>
<Form.Item name="recurrenceEndDate" label="Recurrence End Date">
<DatePicker value={recurrenceEndDate} />
<DatePicker value={recurrenceEndDate} onChange={handleRecurrenceEndDateChange} />
</Form.Item>
</>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/ItemTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ const ItemTable: React.FC<ItemTableProps> = ({ itemType }) => {
<tr key={item.id}>
<td>{item.description}</td>
<td>{item.amount}</td>
{itemType === 'expenses' && <td>{item.category}</td>}
<td>{item.date}</td>
{itemType === 'expenses' && <td>{item.category || '-'}</td>}
<td>{item.date ?? '-'}</td>
<td>
<Dropdown
dropdownRender={() => (
Expand Down
10 changes: 5 additions & 5 deletions src/types/Expense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ export interface Expense {
id: number;
description: string;
amount: number;
category: string;
date: string;
recurring: boolean;
recurrenceType: string | null;
recurrenceEndDate: string | null;
category?: string;
date?: string;
recurring?: boolean;
recurrenceType?: string | null;
recurrenceEndDate?: string | null;
}

0 comments on commit 595ae7f

Please sign in to comment.