diff --git a/expense_tracker/.firebase/hosting.YnVpbGRcd2Vi.cache b/expense_tracker/.firebase/hosting.YnVpbGRcd2Vi.cache new file mode 100644 index 0000000..61b65e7 --- /dev/null +++ b/expense_tracker/.firebase/hosting.YnVpbGRcd2Vi.cache @@ -0,0 +1,20 @@ +favicon.png,1669978261902,0cab6e3dd5a9f008afdd133e1e1207cf65f2f2a10eb6712e3c209d8a5f76425a +index.html,1670601605436,ef4dc2bab6b664bea53656b1acdad21d2ede8ecca888d628d231b9ba357ac059 +manifest.json,1670245010056,1e674500f8f4aca1f9a7b5e738296217aaa044b4072139b8101f57e4a40a7c7d +version.json,1670601605165,e38172972d2c99f92cc5239f9e45d1bb750afe69e03ee5fbc36aef12f474113e +assets/AssetManifest.json,1670601605284,4dc0ac6e0cd8a5aca4a340ed626f7a9410f9abf8c874ee5e6ace847171e71c7a +flutter_service_worker.js,1670601606388,be3d7a14067bbcbc77c1287c79a25c47998bcc36053f25e66fa243ca75b0b64e +assets/FontManifest.json,1670601605284,638dde6f87e8796f3054f78065f73846fc5e170e081d2501d08e3ceaa300edb5 +flutter.js,1670550530366,de4a72d96fd92095a331d197e64ba3a4f139133a6917d932b8673ffc58ecf059 +icons/Icon-192.png,1669978261987,eaf2464bfb1d192fdd192a616f7b858dee456d573c6ec619648a1dcf2bdddfa6 +icons/Icon-512.png,1669978262008,9cf4cd298ae95acc1f25e97d88aa3f6bbfdf40867ea0f8a854c4393f49d56e64 +icons/Icon-maskable-192.png,1669979083822,196ce9142a3442ab37ae90cd46c3389e4660400c859b81cbb0538a51b39752eb +icons/Icon-maskable-512.png,1669979083813,6833b7c449e0dd24d5e164a53cc4557e643893e675b476b05efcbb9a6aa05bf0 +canvaskit/canvaskit.js,1670443184444,8ff9cbe5dbf69c38eb7c466ad2a03f276996bfafabafa667fb31de3a9ce3161b +canvaskit/profiling/canvaskit.js,1670443184499,6420bd60a37f0870f2d750e80e38eca52602e2664288d1a2ce6f99b399e946a8 +assets/packages/cupertino_icons/assets/CupertinoIcons.ttf,1669806483339,007720e2ea8128f223e5f1a08073b8f40df49b41dac35727107ab73dc4488ae0 +assets/NOTICES,1670601605285,6e47265c423c0e680edfbcb4779b357f01aade3d65573837e6bea0d61f0a94ae +assets/fonts/MaterialIcons-Regular.otf,1669979171221,26ccc86b05c476a6b792d6abae012d693ce5e7effabb62ca623c44b7ca264aae +main.dart.js,1670601604062,869c1947270e1f9605d94f283fd089e36aabb3ba15fde678a641336b5c8d77a3 +canvaskit/canvaskit.wasm,1670443184493,c02c266899510d8fe7228271e0c9219e42f3f81c38d2cf677abb3893f2bcb119 +canvaskit/profiling/canvaskit.wasm,1670443184563,6b433eb1c13eea60832b8f784715a0305ca764effb0443a8134485495203341e diff --git a/expense_tracker/.firebaserc b/expense_tracker/.firebaserc new file mode 100644 index 0000000..95e100d --- /dev/null +++ b/expense_tracker/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "expense-tracker-5f15c" + } +} diff --git a/expense_tracker/README.md b/expense_tracker/README.md index ff31c81..d8cd085 100644 --- a/expense_tracker/README.md +++ b/expense_tracker/README.md @@ -17,30 +17,44 @@ samples, guidance on mobile development, and a full API reference. # Hosting server link +https://expense-tracker-5f15c.web.app/#/ +# Manager credential +manager2@gmail.com +123456789 + +# user can register and use that details OR + +test11@gmail.com +123456789 + +# Design figma +https://www.figma.com/file/RkLBWp7peRLPpF0yoH3FuH/Expense-Tracker?node-id=0%3A1&t=zY1LcmiAi9Gkz18P-1 # PWA link +https://expenses-track.surge.sh/#/ + # Git hub link https://github.coventry.ac.uk/suresha9/Expense-tracker.git # Test suits -Test caseId Test Scenario Testcase title pre-requisites Test Steps Expected result Actual resut +Test caseId Test Scenario Testcase title pre-requisites Test Steps Expected result Actual resut -TC_001 Register Register to account Move to home page 1.Click on Signup text 1.Move to signup page 1.Move to signup page +TC_001 user-Register Register to account Move to home page 1.Click on Signup text 1.Move to signup page 1.Move to signup page 2.Enter details 2.save details to database 2.save details to database 3.click on sign up 3.Move to Home 3.Move to Home move to Home screen ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -TC_002 Login Login to account move to home page 1.Enter the register details 1.check register data 1.check register data - 2.if data exist move to home 2.if data exist move to home +TC_002 user-Login Login to account move to home page 1.Enter the register details 1.check register data 1.check register data + 2.if data exist move to home 2.if data exist move to home 2.click to sign in 3.check databse for data 4.if data exist move to home --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -TC_003 Forget password Forgot password move to signin 1.click on forgotpassword 1.move to forgot password 1.move to forgot password +TC_003 user-Forget password Forgot password move to signin 1.click on forgotpassword 1.move to forgot password 1.move to forgot password 2.sent link and rest password 2.sent link and rest password 3.after reset click on button 3.after reset click on button 4.move to sign in 4.move to sign in diff --git a/expense_tracker/assets/images/logo.png b/expense_tracker/assets/images/logo.png index abe4752..8bc1033 100644 Binary files a/expense_tracker/assets/images/logo.png and b/expense_tracker/assets/images/logo.png differ diff --git a/expense_tracker/firebase.json b/expense_tracker/firebase.json new file mode 100644 index 0000000..6603732 --- /dev/null +++ b/expense_tracker/firebase.json @@ -0,0 +1,16 @@ +{ + "hosting": { + "public": "build/web", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} diff --git a/expense_tracker/lib/Components/mnavbar.dart b/expense_tracker/lib/Components/mnavbar.dart index eba4775..a5597e0 100644 --- a/expense_tracker/lib/Components/mnavbar.dart +++ b/expense_tracker/lib/Components/mnavbar.dart @@ -125,19 +125,25 @@ class MobileNavbar extends StatelessWidget { ), Padding( padding: const EdgeInsets.all(12.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + child: Wrap( + // mainAxisAlignment: MainAxisAlignment.center, children: [ GestureDetector( onTap: () => { Navigator.push(context, MaterialPageRoute(builder: (context) => MainPage())) }, - child: const Text( - "Home", - style: TextStyle(color: Colors.white, fontSize: 20), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: const Text( + "Home", + style: TextStyle(color: Colors.white, fontSize: 20), + ), ), ), + const SizedBox( + width: 30, + ), GestureDetector( onTap: () => { Navigator.push( @@ -145,9 +151,12 @@ class MobileNavbar extends StatelessWidget { MaterialPageRoute( builder: (context) => ActivityManager())) }, - child: const Text( - "Activity", - style: TextStyle(color: Colors.white, fontSize: 20), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: const Text( + "Activity", + style: TextStyle(color: Colors.white, fontSize: 20), + ), ), ), const SizedBox( @@ -158,25 +167,31 @@ class MobileNavbar extends StatelessWidget { Navigator.push(context, MaterialPageRoute(builder: (context) => Profile())) }, - child: const Text( - "Profile", - style: TextStyle(color: Colors.white, fontSize: 20), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: const Text( + "Profile", + style: TextStyle(color: Colors.white, fontSize: 20), + ), ), ), const SizedBox( width: 30, ), - MaterialButton( - color: Colors.pink, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20.0))), - onPressed: () => { - Navigator.push(context, - MaterialPageRoute(builder: (context) => getstarted())) - }, - child: const Text( - "Get Started", - style: TextStyle(color: Colors.white, fontSize: 20), + Padding( + padding: const EdgeInsets.all(8.0), + child: MaterialButton( + color: Colors.pink, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20.0))), + onPressed: () => { + Navigator.push(context, + MaterialPageRoute(builder: (context) => getstarted())) + }, + child: const Text( + "Get Started", + style: TextStyle(color: Colors.white, fontSize: 20), + ), ), ) ], diff --git a/expense_tracker/lib/Screens/activitymanager.dart b/expense_tracker/lib/Screens/activitymanager.dart index bfabc46..9c22fe4 100644 --- a/expense_tracker/lib/Screens/activitymanager.dart +++ b/expense_tracker/lib/Screens/activitymanager.dart @@ -1,7 +1,7 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_database/firebase_database.dart'; import 'package:flutter/material.dart'; -import '../Components/navbar.dart'; +import '../Components/mnavbar.dart'; import './myhomepage.dart'; // import 'package:firebase_auth/firebase_auth.dart' as firebase_auth; @@ -42,7 +42,7 @@ class _ActivityManagerState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - const Navbar(), + const Mnavbar(), const Padding( padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 40.0), ), @@ -54,169 +54,179 @@ class _ActivityManagerState extends State { style: TextStyle(color: Colors.white), ), ) - : ListView.builder( - itemCount: expenseList.length, - itemBuilder: (context, index) { - var childData = expenseList[index]; - var childDataExpenses = childData.children.toList(); - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Card( - color: Colors.black, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - FutureBuilder( - future: FirebaseDatabase.instance - .ref('users') - .child(childData.key.toString()) - .get(), - builder: (context, snapshot) { - if (snapshot.data == null) { - return Text( - childData.key.toString(), - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold), - ); - } else { - return Text( - snapshot.data! - .child('name') - .value - .toString(), - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold), - ); - } - }, - ), - const Spacer(), - const Icon( - Icons.arrow_downward_outlined, - color: Colors.white, - ) - ], - ), - ), - ), - ListView.builder( - itemCount: childDataExpenses.length, - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (context, index) { - var expense = childDataExpenses[index]; - return Card( - child: Padding( - padding: const EdgeInsets.all(10), - child: Row( - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - '${expense.child('Marchantname').value} - ${expense.child('category').value}', + : Container( + width: 900, + child: ListView.builder( + itemCount: expenseList.length, + itemBuilder: (context, index) { + var childData = expenseList[index]; + var childDataExpenses = childData.children.toList(); + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Card( + color: Colors.black, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + FutureBuilder( + future: FirebaseDatabase.instance + .ref('users') + .child(childData.key.toString()) + .get(), + builder: (context, snapshot) { + if (snapshot.data == null) { + return Text( + childData.key.toString(), style: const TextStyle( + color: Colors.white, fontWeight: FontWeight.bold), - ), - Text( - 'Status : ${expense.child('status').value}'), - Text( - '${expense.child('Description').value}'), - ], - ), - const Spacer(), - Column( - children: [ - Text( - '${expense.child('Amount').value} EUR', + ); + } else { + return Text( + snapshot.data! + .child('name') + .value + .toString(), style: const TextStyle( + color: Colors.white, fontWeight: FontWeight.bold), - ), - ], - ), - const SizedBox(width: 8), - GestureDetector( - onTap: () { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: const Text( - 'Change Status'), - content: const Text( - 'Please choose the status of the expense'), - actions: [ - GestureDetector( - onTap: () { - expense.ref.update({ - 'status': 'Approved' - }); - Navigator.of(context) - .pop(); - }, - child: Container( - padding: - const EdgeInsets - .all(8.0), - color: Colors.green, - child: const Text( - 'Approve', - style: TextStyle( - color: Colors - .white), + ); + } + }, + ), + const Spacer(), + const Icon( + Icons.arrow_downward_outlined, + color: Colors.white, + ) + ], + ), + ), + ), + ListView.builder( + itemCount: childDataExpenses.length, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemBuilder: (context, index) { + var expense = childDataExpenses[index]; + return Card( + child: Padding( + padding: const EdgeInsets.all(10), + child: Row( + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '${expense.child('Marchantname').value} - ${expense.child('category').value}', + style: const TextStyle( + fontWeight: + FontWeight.bold), + ), + Text( + 'Status : ${expense.child('status').value}'), + Text( + '${expense.child('Description').value}'), + ], + ), + const Spacer(), + Column( + children: [ + Text( + '${expense.child('Amount').value} GBP', + style: const TextStyle( + fontWeight: + FontWeight.bold), + ), + ], + ), + const SizedBox(width: 8), + GestureDetector( + onTap: () { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text( + 'Change Status'), + content: const Text( + 'Please choose the status of the expense'), + actions: [ + GestureDetector( + onTap: () { + expense.ref.update({ + 'status': + 'Approved' + }); + Navigator.of( + context) + .pop(); + }, + child: Container( + padding: + const EdgeInsets + .all(8.0), + color: Colors.green, + child: const Text( + 'Approve', + style: TextStyle( + color: Colors + .white), + ), ), ), - ), - GestureDetector( - onTap: () { - expense.ref.update({ - 'status': 'Rejected' - }); - Navigator.of(context) - .pop(); - }, - child: Container( - color: Colors.red, - padding: - const EdgeInsets - .all(8.0), - child: const Text( - 'Reject', - style: TextStyle( - color: Colors - .white), + GestureDetector( + onTap: () { + expense.ref.update({ + 'status': + 'Rejected' + }); + Navigator.of( + context) + .pop(); + }, + child: Container( + color: Colors.red, + padding: + const EdgeInsets + .all(8.0), + child: const Text( + 'Reject', + style: TextStyle( + color: Colors + .white), + ), ), - ), - ) - ], - ); - }); - }, - child: Container( - padding: const EdgeInsets.all(8.0), - color: Colors.grey, - child: const Text( - 'Change Status', - style: TextStyle( - color: Colors.white), + ) + ], + ); + }); + }, + child: Container( + padding: + const EdgeInsets.all(8.0), + color: Colors.grey, + child: const Text( + 'Change Status', + style: TextStyle( + color: Colors.white), + ), ), ), - ), - ], + ], + ), ), - ), - ); - }, - ) - ], - ); - // - }, + ); + }, + ) + ], + ); + // + }, + ), ), ), ], diff --git a/expense_tracker/lib/Screens/getstarted.dart b/expense_tracker/lib/Screens/getstarted.dart index 3eda452..0ee102f 100644 --- a/expense_tracker/lib/Screens/getstarted.dart +++ b/expense_tracker/lib/Screens/getstarted.dart @@ -64,7 +64,8 @@ class getstartedState extends State { Padding( padding: EdgeInsetsDirectional.fromSTEB(20, 0, 0, 0), - child: Text("Name", + child: Text( + "This is a website to add expenses of user and managers can approve the same ", style: TextStyle( color: Color.fromARGB( 255, 255, 255, 255)))), @@ -72,21 +73,6 @@ class getstartedState extends State { ], ), SizedBox(height: 20), - Row( - children: [ - Padding( - padding: - EdgeInsetsDirectional.fromSTEB(20, 0, 0, 0), - child: Text("Email", - style: TextStyle( - color: Color.fromARGB( - 255, 255, 255, 255)))), - SizedBox(width: 30), - Text(user.email!, - style: TextStyle( - color: Color.fromARGB(255, 255, 255, 255))) - ], - ), SizedBox(height: 20), GestureDetector( onTap: () => { diff --git a/expense_tracker/lib/Screens/managerhomepage.dart b/expense_tracker/lib/Screens/managerhomepage.dart index 5e16125..1fd6f8b 100644 --- a/expense_tracker/lib/Screens/managerhomepage.dart +++ b/expense_tracker/lib/Screens/managerhomepage.dart @@ -27,14 +27,24 @@ class ManagerHomePageState extends State { }); } - calculateTotal(List expenseList) { + calculateTotalPerUser(List expenseList) { var value = 0.0; for (int i = 0; i < expenseList.length; i++) { value += double.tryParse(expenseList[i].child('Amount').value.toString()) ?? 0.0; } - total += value; + return value; + } + + calculateTotal(List expenseList) { + var value = 0.0; + for (int i = 0; i < expenseList.length; i++) { + for (int j = 0; j < expenseList[i].children.toList().length; j++) { + var child = expenseList[i].children.toList()[j]; + value += double.tryParse(child.child('Amount').value.toString()) ?? 0.0; + } + } return value; } @@ -63,32 +73,32 @@ class ManagerHomePageState extends State { padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 40.0), ), const SizedBox(height: 80), - ListView.builder( - itemCount: expenseList.length, - physics: NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (context, index) { - var userExpense = expenseList[index]; - return Column( - mainAxisSize: MainAxisSize.max, - children: [ - Container( - width: 900, - decoration: const BoxDecoration( - color: Color.fromARGB(115, 0, 0, 0), - ), - child: Column( + Container( + width: 900, + decoration: const BoxDecoration( + color: Color.fromARGB(115, 0, 0, 0), + ), + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + const SizedBox(height: 60), + const Text( + 'Complete Expenses', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 50, + color: Color.fromARGB(255, 255, 255, 255)), + ), + const SizedBox(height: 30), + ListView.builder( + itemCount: expenseList.length, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemBuilder: (context, index) { + var userExpense = expenseList[index]; + return Column( mainAxisSize: MainAxisSize.max, children: [ - const SizedBox(height: 60), - const Text( - 'Complete Expenses', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 50, - color: Color.fromARGB(255, 255, 255, 255)), - ), - const SizedBox(height: 30), Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.max, @@ -96,11 +106,6 @@ class ManagerHomePageState extends State { const Padding( padding: EdgeInsetsDirectional.fromSTEB( 0, 0, 0, 0), - child: Icon( - Icons.favorite, - color: Colors.pink, - size: 24.0, - ), ), Padding( padding: const EdgeInsetsDirectional.fromSTEB( @@ -138,7 +143,7 @@ class ManagerHomePageState extends State { padding: const EdgeInsetsDirectional.fromSTEB( 20, 0, 0, 0), child: Text( - '${calculateTotal(userExpense.children.toList())} EUR', + '${calculateTotalPerUser(userExpense.children.toList())} GBP', style: const TextStyle( fontSize: 24, color: Color.fromARGB( @@ -147,41 +152,37 @@ class ManagerHomePageState extends State { ], ), const SizedBox(height: 30), - Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - const Padding( - padding: EdgeInsetsDirectional.fromSTEB( - 0, 0, 0, 0), - ), - const Padding( - padding: EdgeInsetsDirectional.fromSTEB( - 20, 0, 0, 0), - child: Text('Total :', - style: TextStyle( - fontSize: 24, - color: Color.fromARGB( - 255, 255, 255, 255))), - ), - Padding( - padding: const EdgeInsetsDirectional.fromSTEB( - 20, 0, 0, 0), - child: Text('$total GBP', - style: const TextStyle( - fontSize: 24, - color: Color.fromARGB( - 255, 255, 255, 255))), - ), - ], - ), - const SizedBox(height: 60), ], + ); + }, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + const Padding( + padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0), + ), + const Padding( + padding: EdgeInsetsDirectional.fromSTEB(20, 0, 0, 0), + child: Text('Total :', + style: TextStyle( + fontSize: 24, + color: Color.fromARGB(255, 255, 255, 255))), + ), + Padding( + padding: + const EdgeInsetsDirectional.fromSTEB(20, 0, 0, 0), + child: Text('${calculateTotal(expenseList)} GBP', + style: const TextStyle( + fontSize: 24, + color: Color.fromARGB(255, 255, 255, 255))), ), - ), - ], - ); - }, + ], + ), + const SizedBox(height: 60), + ], + ), ), ], ),