├── src
├── App.css
├── index.css
├── main.jsx
├── components
│ ├── TotalExpenses.jsx
│ ├── ExpenseList.jsx
│ └── ExpenseForm.jsx
├── App.jsx
└── assets
│ └── react.svg
├── postcss.config.js
├── vite.config.js
├── tailwind.config.js
├── .gitignore
├── index.html
├── README.md
├── package.json
├── eslint.config.js
└── public
└── vite.svg
/src/App.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | };
9 |
--------------------------------------------------------------------------------
/src/main.jsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react'
2 | import { createRoot } from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/src/components/TotalExpenses.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const TotalExpenses = ({ expenses }) => {
4 | const total = expenses.reduce((sum, expense) => sum + parseFloat(expense.amount), 0).toFixed(2);
5 | return
Total Expenses: ${total}
;
6 | };
7 |
8 | export default TotalExpenses;
9 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Expense Tracker App
2 | Expense Tracker is a simple expense tracker app built in React.js and Tailwind CSS.
3 |
4 | Installation Instructions
5 |
6 | - Clone this repository.
7 | - Open it in your development environment.
8 | - Run
npm install to install the node modules.
9 | - Finally, run
npm run dev to run it in your browser.
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/ExpenseList.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const ExpenseList = ({ expenses, filterCategory }) => {
4 | const filteredExpenses = filterCategory ? expenses.filter(exp => exp.category === filterCategory) : expenses;
5 |
6 | return (
7 |
17 | );
18 | };
19 |
20 | export default ExpenseList;
21 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "expense-tracker",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint .",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "autoprefixer": "^10.4.20",
14 | "postcss": "^8.4.47",
15 | "react": "^18.3.1",
16 | "react-dom": "^18.3.1",
17 | "tailwindcss": "^3.4.14"
18 | },
19 | "devDependencies": {
20 | "@eslint/js": "^9.11.1",
21 | "@types/react": "^18.3.10",
22 | "@types/react-dom": "^18.3.0",
23 | "@vitejs/plugin-react": "^4.3.2",
24 | "eslint": "^9.11.1",
25 | "eslint-plugin-react": "^7.37.0",
26 | "eslint-plugin-react-hooks": "^5.1.0-rc.0",
27 | "eslint-plugin-react-refresh": "^0.4.12",
28 | "globals": "^15.9.0",
29 | "vite": "^5.4.8"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js'
2 | import globals from 'globals'
3 | import react from 'eslint-plugin-react'
4 | import reactHooks from 'eslint-plugin-react-hooks'
5 | import reactRefresh from 'eslint-plugin-react-refresh'
6 |
7 | export default [
8 | { ignores: ['dist'] },
9 | {
10 | files: ['**/*.{js,jsx}'],
11 | languageOptions: {
12 | ecmaVersion: 2020,
13 | globals: globals.browser,
14 | parserOptions: {
15 | ecmaVersion: 'latest',
16 | ecmaFeatures: { jsx: true },
17 | sourceType: 'module',
18 | },
19 | },
20 | settings: { react: { version: '18.3' } },
21 | plugins: {
22 | react,
23 | 'react-hooks': reactHooks,
24 | 'react-refresh': reactRefresh,
25 | },
26 | rules: {
27 | ...js.configs.recommended.rules,
28 | ...react.configs.recommended.rules,
29 | ...react.configs['jsx-runtime'].rules,
30 | ...reactHooks.configs.recommended.rules,
31 | 'react/jsx-no-target-blank': 'off',
32 | 'react-refresh/only-export-components': [
33 | 'warn',
34 | { allowConstantExport: true },
35 | ],
36 | },
37 | },
38 | ]
39 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import ExpenseForm from './components/ExpenseForm';
3 | import ExpenseList from './components/ExpenseList';
4 | import TotalExpenses from './components/TotalExpenses';
5 |
6 | const App = () => {
7 | const [expenses, setExpenses] = useState([]);
8 | const [filterCategory, setFilterCategory] = useState('');
9 |
10 | useEffect(() => {
11 | const storedExpenses = JSON.parse(localStorage.getItem('expenses')) || [];
12 | setExpenses(storedExpenses);
13 | }, []);
14 |
15 | useEffect(() => {
16 | localStorage.setItem('expenses', JSON.stringify(expenses));
17 | }, [expenses]);
18 |
19 | const addExpense = (expense) => {
20 | setExpenses([...expenses, expense]);
21 | };
22 |
23 | return (
24 |
25 |
26 |
Expense Tracker
27 |
28 | setFilterCategory(e.target.value)}
32 | className="w-full p-2 mt-4 mb-6 border border-gray-300 rounded shadow-sm focus:outline-none focus:border-pink-400"
33 | />
34 |
35 |
36 |
37 |
38 | );
39 | };
40 |
41 | export default App;
42 |
--------------------------------------------------------------------------------
/src/components/ExpenseForm.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | const ExpenseForm = ({ addExpense }) => {
4 | const [amount, setAmount] = useState('');
5 | const [category, setCategory] = useState('');
6 | const [date, setDate] = useState('');
7 | const [description, setDescription] = useState('');
8 |
9 | const handleSubmit = (e) => {
10 | e.preventDefault();
11 | if (amount && category && date) {
12 | addExpense({ amount, category, date, description });
13 | setAmount('');
14 | setCategory('');
15 | setDate('');
16 | setDescription('');
17 | }
18 | };
19 |
20 | return (
21 |
55 | );
56 | };
57 |
58 | export default ExpenseForm;
59 |
--------------------------------------------------------------------------------
/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------