diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..04296ec
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,23 @@
+# Supabase Configuration
+# Sign up at https://supabase.io to get your project URL and anon key
+REACT_APP_SUPABASE_URL=https://your-supabase-project.supabase.co
+REACT_APP_SUPABASE_ANON_KEY=your-supabase-anon-key-here
+
+# Database Password (for reference - not used directly in app)
+SUPABASE_DB_PASSWORD=your-database-password-here
+
+# Application Settings
+REACT_APP_APP_NAME=Time Tracker
+REACT_APP_VERSION=1.0.0
+
+# Development Settings
+GENERATE_SOURCEMAP=false
+
+# Instructions:
+# 1. Copy this file to .env
+# 2. Replace placeholder values with your actual credentials
+# 3. Restart the development server after making changes
+
+# Security Note:
+# Never commit .env file to version control
+# Only variables prefixed with REACT_APP_ are embedded in the client bundle
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 4d29575..c2d6a6b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,7 +17,12 @@
.env.development.local
.env.test.local
.env.production.local
+.env
+
+# Additional environment files
+.env.*
+!.env.example
npm-debug.log*
yarn-debug.log*
-yarn-error.log*
+yarn-error.log*
\ No newline at end of file
diff --git a/README.md b/README.md
index 58beeac..b2af5b4 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,144 @@
-# Getting Started with Create React App
+# Time Tracker App
+
+A React-based time tracking application with user authentication and session management.
+
+## Features
+
+- User authentication system with Supabase Auth
+- Start/stop time tracking functionality
+- Pause/resume functionality for breaks
+- Session history management
+- Edit current and past sessions
+- Create new sessions with simplified time input
+- Integration with Supabase for data persistence
+- Responsive design for desktop and mobile
+
+## Pages
+
+1. **Login/Register Page** - Secure authentication entry point
+2. **Dashboard** - Main page with timer controls
+3. **Session History** - View, edit, and create sessions
+
+## Setup Instructions
+
+1. Clone the repository (if applicable)
+2. Install dependencies:
+ ```
+ npm install
+ ```
+3. Set up environment variables:
+ - Copy `.env.example` to `.env`
+ - Update the values in `.env` with your Supabase credentials:
+ ```
+ REACT_APP_SUPABASE_URL=your_supabase_project_url_here
+ REACT_APP_SUPABASE_ANON_KEY=your_supabase_anon_key_here
+ ```
+4. Start the development server:
+ ```
+ npm start
+ ```
+
+## Database Setup
+
+### Supabase Tables
+
+Create these tables in your Supabase project:
+
+#### Users Table
+```sql
+-- Users table (handled by Supabase Auth)
+-- Supabase automatically creates auth.users table
+```
+
+#### Timers Table
+```sql
+-- Create timers table
+create table if not exists timers (
+ id uuid primary key default gen_random_uuid(),
+ user_id uuid references auth.users(id) not null,
+ start_time timestamptz not null,
+ end_time timestamptz,
+ duration_ms integer,
+ pauses json,
+ created_at timestamptz default now()
+);
+
+-- Enable RLS (Row Level Security)
+alter table timers enable row level security;
+
+-- Create policy to allow users to access their own timers only
+create policy "Users can access their own timers" on timers
+ for all using (auth.uid() = user_id);
+
+-- Grant permissions
+grant usage on schema public to anon, authenticated;
+grant all on table timers to anon, authenticated;
+```
+
+## Session Management Features
+
+### Creating New Sessions
+- Click "Create New Session" in Session History
+- Select date and enter start/end times (HH:MM format)
+- Add pauses with start/end times as needed
+- Save to store in Supabase database
+
+### Editing Sessions
+- Edit current active session
+- Edit past sessions from history
+- Modify start/end times and pause periods
+- Changes automatically saved to database
+
+### Timer Controls
+- Start/Stop schedule tracking
+- Take breaks with Pause/Resume functionality
+- Real-time work time calculation (excluding pause time)
+
+## Security
+
+- Environment variables are stored in `.env` (excluded from git)
+- Sensitive data never stored in browser localStorage or sessionStorage
+- All session data persists only in user session and external database
+- Review `.gitignore` to ensure sensitive files are not committed
+- Supabase Auth handles user authentication securely
+
+## Implementation Details
+
+- Built with React and React Router for navigation
+- Uses Context API for state management
+- Implements a clean, responsive UI with CSS
+- Session data persists in user session and Supabase database
+- Integrates with Supabase API for data persistence and authentication
+
+## File Structure
+
+```
+src/
+├── components/ # Reusable UI components
+├── context/ # Authentication and state context
+├── pages/ # Page components (Login, Dashboard, Sessions)
+├── services/ # API integration services
+└── App.js # Main app component with routing
+```
+
+## Database Integration
+
+The app includes a service layer for Supabase integration:
+- Sessions are saved to the database when stopped
+- Session history is loaded from the database on login
+- All database operations are handled through the sessionService
+- User authentication is managed by Supabase Auth
+
+To connect to your own Supabase project:
+1. Create a Supabase account at https://supabase.io
+2. Create a new project
+3. Get your project URL and anon key from project settings
+4. Create the required tables using the SQL provided above
+5. Update the environment variables with your credentials
+
+---
+
+# Original Create React App Documentation
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
@@ -67,4 +207,4 @@ This section has moved here: [https://facebook.github.io/create-react-app/docs/d
### `npm run build` fails to minify
-This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
+This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index f6c92a6..4d5bb56 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,12 +8,17 @@
"name": "time-tracker-app",
"version": "0.1.0",
"dependencies": {
+ "@fortawesome/free-solid-svg-icons": "^7.2.0",
+ "@fortawesome/react-fontawesome": "^3.3.0",
+ "@supabase/supabase-js": "^2.103.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^13.5.0",
+ "axios": "^1.15.0",
"react": "^19.2.5",
"react-dom": "^19.2.5",
+ "react-router-dom": "^7.14.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}
@@ -2456,6 +2461,53 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@fortawesome/fontawesome-common-types": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-7.2.0.tgz",
+ "integrity": "sha512-IpR0bER9FY25p+e7BmFH25MZKEwFHTfRAfhOyJubgiDnoJNsSvJ7nigLraHtp4VOG/cy8D7uiV0dLkHOne5Fhw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/fontawesome-svg-core": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.2.0.tgz",
+ "integrity": "sha512-6639htZMjEkwskf3J+e6/iar+4cTNM9qhoWuRfj9F3eJD6r7iCzV1SWnQr2Mdv0QT0suuqU8BoJCZUyCtP9R4Q==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "7.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/free-solid-svg-icons": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-7.2.0.tgz",
+ "integrity": "sha512-YTVITFGN0/24PxzXrwqCgnyd7njDuzp5ZvaCx5nq/jg55kUYd94Nj8UTchBdBofi/L0nwRfjGOg0E41d2u9T1w==",
+ "license": "(CC-BY-4.0 AND MIT)",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "7.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/react-fontawesome": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-3.3.0.tgz",
+ "integrity": "sha512-EHmHeTf8WgO29sdY3iX/7ekE3gNUdlc2RW6mm/FzELlHFKfTrA9S4MlyquRR+RRCRCn8+jXfLFpLGB2l7wCWyw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ },
+ "peerDependencies": {
+ "@fortawesome/fontawesome-svg-core": "~6 || ~7",
+ "react": "^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
@@ -3100,6 +3152,113 @@
"@sinonjs/commons": "^1.7.0"
}
},
+ "node_modules/@supabase/auth-js": {
+ "version": "2.103.0",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.103.0.tgz",
+ "integrity": "sha512-6zAanO6c+6gpHOlt5Lb9TlBBkJdZiUWkWCJKAxzkywBDcwaHlLJKXnjQGX6GyVCyKRR1e7sTq4re/yRTH6U/9A==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "2.8.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@supabase/functions-js": {
+ "version": "2.103.0",
+ "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.103.0.tgz",
+ "integrity": "sha512-YrneV2NjskUkkmkZ2Jt2n3elBgbWzV4Y1M9MM370z2Zd5ZPFqFbY8KIoPwuNjtAGE9YrpKBxnbZqeF07BiN9Og==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "2.8.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@supabase/phoenix": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@supabase/phoenix/-/phoenix-0.4.0.tgz",
+ "integrity": "sha512-RHSx8bHS02xwfHdAbX5Lpbo6PXbgyf7lTaXTlwtFDPwOIw64NnVRwFAXGojHhjtVYI+PEPNSWwkL90f4agN3bw==",
+ "license": "MIT"
+ },
+ "node_modules/@supabase/postgrest-js": {
+ "version": "2.103.0",
+ "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.103.0.tgz",
+ "integrity": "sha512-rC3sRxYdPZymkp2CZR1MiNQgbOleD01bGsW8VxEKRR5nMkLZ1NgAS1QTQf78Wh30czFyk505ZYr9Od8/mWT2TA==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "2.8.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@supabase/realtime-js": {
+ "version": "2.103.0",
+ "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.103.0.tgz",
+ "integrity": "sha512-gcPtXzZ6izyyBVf2of7K3dEt8CScPJn8VcSlQq6oWL9QoE1kqfQl0oFrOMHd5qrcADewxI7OxxosLB8W4XqtIQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/phoenix": "^0.4.0",
+ "@types/ws": "^8.18.1",
+ "tslib": "2.8.1",
+ "ws": "^8.18.2"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@supabase/realtime-js/node_modules/ws": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
+ "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@supabase/storage-js": {
+ "version": "2.103.0",
+ "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.103.0.tgz",
+ "integrity": "sha512-DHmlvdAXwtOmZNbkIZi4lkobPR3XjIzoOgzoz5duMf6G+sDeY015YrzMJCnqdccuYr7X5x4yYuSwF//RoN2dvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "iceberg-js": "^0.8.1",
+ "tslib": "2.8.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@supabase/supabase-js": {
+ "version": "2.103.0",
+ "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.103.0.tgz",
+ "integrity": "sha512-j/6q5+LtXbR/YOLSLhy7Na74RD1cV2v+KwIIuuqMEjk1JpLEEyu0ynwDHpGoxMncDQl+R5FogaVqZm+85lZvtw==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/auth-js": "2.103.0",
+ "@supabase/functions-js": "2.103.0",
+ "@supabase/postgrest-js": "2.103.0",
+ "@supabase/realtime-js": "2.103.0",
+ "@supabase/storage-js": "2.103.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
"node_modules/@surma/rollup-plugin-off-main-thread": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
@@ -4803,6 +4962,33 @@
"node": ">=4"
}
},
+ "node_modules/axios": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz",
+ "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.15.11",
+ "form-data": "^4.0.5",
+ "proxy-from-env": "^2.1.0"
+ }
+ },
+ "node_modules/axios/node_modules/form-data": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
+ "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/axobject-query": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
@@ -9020,6 +9206,15 @@
"node": ">=10.17.0"
}
},
+ "node_modules/iceberg-js": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz",
+ "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -13472,6 +13667,15 @@
"node": ">= 0.10"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
+ "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/psl": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
@@ -13763,6 +13967,57 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "7.14.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.14.0.tgz",
+ "integrity": "sha512-m/xR9N4LQLmAS0ZhkY2nkPA1N7gQ5TUVa5n8TgANuDTARbn1gt+zLPXEm7W0XDTbrQ2AJSJKhoa6yx1D8BcpxQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.14.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.14.0.tgz",
+ "integrity": "sha512-2G3ajSVSZMEtmTjIklRWlNvo8wICEpLihfD/0YMDxbWK2UyP5EGfnoIn9AIQGnF3G/FX0MRbHXdFcD+rL1ZreQ==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.14.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/react-router/node_modules/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -14641,6 +14896,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
+ "license": "MIT"
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
diff --git a/package.json b/package.json
index 17f3cd1..2354cbb 100644
--- a/package.json
+++ b/package.json
@@ -3,12 +3,17 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@fortawesome/free-solid-svg-icons": "^7.2.0",
+ "@fortawesome/react-fontawesome": "^3.3.0",
+ "@supabase/supabase-js": "^2.103.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^13.5.0",
+ "axios": "^1.15.0",
"react": "^19.2.5",
"react-dom": "^19.2.5",
+ "react-router-dom": "^7.14.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
@@ -16,7 +21,8 @@
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
- "eject": "react-scripts eject"
+ "eject": "react-scripts eject",
+ "setup": "node setup.js"
},
"eslintConfig": {
"extends": [
diff --git a/public/LOGO_FICOSA.svg b/public/LOGO_FICOSA.svg
new file mode 100644
index 0000000..ee22b3e
--- /dev/null
+++ b/public/LOGO_FICOSA.svg
@@ -0,0 +1,56 @@
+
+
+
diff --git a/public/favicon.ico b/public/favicon.ico
index a11777c..45952a3 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ
diff --git a/public/index.html b/public/index.html
index aa069f2..f3e7dee 100644
--- a/public/index.html
+++ b/public/index.html
@@ -9,7 +9,7 @@
name="description"
content="Web site created using create-react-app"
/>
-
+