Monity is a simple and intuitive digital banking app designed specifically for the Nigerian market. It provides users with seamless banking experiences, including account management, money transfers, and transaction tracking. This README provides an overview of the app's features, installation instructions, and space for screenshots showcasing the user interface.
Sign Up: New users can create an account using their email and password. Login: Existing users can log in with their credentials. Profile Completion: After logging in, users complete their profile by providing additional details.
Profile Setup: Users can update their profile information, change passwords, and manage security settings. Passcode Setup: Users set a 4-digit passcode for secure banking transactions.
View Transactions: Users can view all their transactions grouped by date. Send Money: Users can send money to other Monity users. Request Money: Users can request money from other Monity users. Transaction Notifications: Users receive notifications about their transactions.
View Balance: Users can view their account balance. Top-Up Balance: Users can top-up their account balance.
App Passcode: Users can set and change their app passcode for additional security.
email: infotezma@gmail.com password Babcock135790 passcode: 1357
email: divzeh001@gmail.com password Babcock135790 passcode: 1357
- Clone the Repository:
bash Copy code git clone https://github.com/yourusername/monity.git cd monity Install Dependencies:
bash Copy code flutter pub get Set Up Supabase:
Create a Supabase project. Set up authentication and database tables as required by the app. Update the lib/constants.dart file with your Supabase URL and API key. Run the App:
bash Copy code flutter run
Sure, here’s a detailed list of the tables and functions created for Monity, along with brief descriptions of their purpose:
-
auth.users
- Description: This is the default table for storing user authentication information, including email and password.
-
profile_info
- Description: Stores additional user information such as first name, last name, profile picture, and other personal details.
- Columns:
id
: Foreign key linking toauth.users
.first_name
: User's first name.last_name
: User's last name.profile_picture
: URL to the user's profile picture.account_number
: 11-digit unique account number.balance
: User's account balance.
-
user_passcodes
- Description: Stores the 4-digit passcodes for users to secure their banking transactions.
- Columns:
user_id
: Foreign key linking toauth.users
.passcode
: Encrypted 4-digit passcode.
-
transaction_logs_with_names
- Description: Stores transaction logs with detailed information about each transaction.
- Columns:
transaction_id
: Unique identifier for each transaction.timestamp
: The date and time of the transaction.sender_profile_id
: Foreign key linking to the sender's profile.recipient_profile_id
: Foreign key linking to the recipient's profile.amount
: The transaction amount.transaction_type
: Type of transaction (debit or credit).transaction_reference
: 20-character unique reference for the transaction.transaction_status
: Status of the transaction (completed, pending, etc.).sender_name
: Name of the sender.recipient_name
: Name of the recipient.
-
transaction_receipt
- Description: Stores transaction receipts containing the reference and status of each transaction.
- Columns:
transaction_reference
: 20-character unique reference.transaction_status
: Status of the transaction (completed, pending, etc.).
-
generate_account_number
- Description: Generates a random 11-digit account number for new users.
- Implementation:
CREATE OR REPLACE FUNCTION generate_account_number() RETURNS TRIGGER AS $$ BEGIN NEW.account_number := floor(random() * 100000000000)::integer; RETURN NEW; END; $$ LANGUAGE plpgsql;
-
trigger_generate_account_number
- Description: Trigger to automatically call
generate_account_number
when a new profile is created. - Implementation:
CREATE TRIGGER trigger_generate_account_number BEFORE INSERT ON profile_info FOR EACH ROW EXECUTE FUNCTION generate_account_number();
- Description: Trigger to automatically call
-
send_transaction_notification
- Description: Sends a push notification to users when a transaction occurs.
- Implementation:
CREATE OR REPLACE FUNCTION send_transaction_notification() RETURNS TRIGGER AS $$ BEGIN PERFORM pg_notify('transaction_channel', json_build_object( 'user_id', NEW.recipient_profile_id, 'message', 'You have received a transaction of ' || NEW.amount )::text); RETURN NEW; END; $$ LANGUAGE plpgsql;
-
trigger_send_transaction_notification
- Description: Trigger to automatically call
send_transaction_notification
when a new transaction log is inserted. - Implementation:
CREATE TRIGGER trigger_send_transaction_notification AFTER INSERT ON transaction_logs_with_names FOR EACH ROW EXECUTE FUNCTION send_transaction_notification();
- Description: Trigger to automatically call
-
Fetching User Profile Information
- Description: Retrieves the profile information for the current user.
- Implementation:
Future<Map<String, dynamic>?> getUserProfileInfo() async { final response = await supabase .from('profile_info') .select('*') .eq('id', Supabase.instance.client.auth.currentUser?.id) .single(); return response.data; }
-
Fetching Transactions
- Description: Retrieves transaction logs related to the current user.
- Implementation:
Future<List<Map<String, dynamic>>> fetchTransactions(String profileId) async { final response = await supabase .from('transaction_logs_with_names') .select('*') .or('sender_profile_id.eq.$profileId,recipient_profile_id.eq.$profileId') .order('timestamp', ascending: false); return response; }
-
Grouping Transactions by Date
- Description: Groups transactions by date for display in the app.
- Implementation:
List<Map<String, dynamic>> groupTransactionsByDate( List<Map<String, dynamic>> transactions, String userId) { final groupedTransactions = <String, List<Map<String, dynamic>>>{}; for (var transaction in transactions) { if (transaction['sender_profile_id'] == userId) { final timestamp = DateTime.parse(transaction['timestamp']); final dateKey = _formatDateKey(timestamp); if (groupedTransactions.containsKey(dateKey)) { groupedTransactions[dateKey]!.add(transaction); } else { groupedTransactions[dateKey] = [transaction]; } } } return groupedTransactions.entries.map((entry) { return { 'date': entry.key, 'transactions': entry.value, }; }).toList(); } String _formatDateKey(DateTime date) { final now = DateTime.now(); final today = DateTime(now.year, now.month, now.day); final transactionDate = DateTime(date.year, date.month, date.day); if (transactionDate == today) { return 'Today'; } else { return DateFormat('MMMM dd, yyyy').format(date); } }
thank you, please leave a star!