forked from Adrozs/The_Bank
-
Notifications
You must be signed in to change notification settings - Fork 0
/
UserFunctions.cs
659 lines (558 loc) · 28.4 KB
/
UserFunctions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
using Microsoft.EntityFrameworkCore;
using The_Bank.Data;
using The_Bank.Models;
using The_Bank.Utilities;
using NAudio.Wave;
namespace The_Bank
{
public class UserFunctions
{
public static void UserMenu(BankContext outerContext, string userName)
{
int menuSelection = 0; // Start from the first option
bool isLoggedIn = true; // When user chooses "Log Out" this turns to false and exits loop to then go back to login screen
using (BankContext context = new BankContext())
{
while (isLoggedIn)
{
//Option menu
MenuFunctions.header();
Console.WriteLine("\t\t\t ::Main Menu::");
Console.WriteLine("\t\tChoose one of the following options:");
MenuFunctions.divider();
// Puts all menu options into an array
string[] MenuOptions = {"View all of your accounts and balance", "Transfer Balance", "Withdrawal", "Deposit", "Open new account", "Change PIN", "Log out" };
for (int i = 0; i < 7; i++) //Forloop to change color on the option the arrow "goes" to.
{
if (i == menuSelection) // so when menuSelection is for exemple "2" the second option will turn darkgrey
{
Console.ForegroundColor = ConsoleColor.DarkGray;
}
//// Prints all the options in the array along with the pointer arrow if on the current selection
Console.WriteLine($"\t\t{MenuOptions[i]}{(menuSelection == i ? " <--" : "")}");
Console.ResetColor(); // Reset color to default
}
MenuFunctions.footer();
//"Listen" to keystrokes from the user
ConsoleKeyInfo key = Console.ReadKey(true);
//Handles the arrow keys to move up and down the menu
if (key.Key == ConsoleKey.UpArrow && menuSelection > 0)
{
menuSelection--;
Sound.PlaySound("navSound.wav");
}
else if (key.Key == ConsoleKey.DownArrow && menuSelection < 6)
{
menuSelection++;
Sound.PlaySound("navSound.wav");
}
else if (key.Key == ConsoleKey.Enter)
{
// If logout is selected don't play the enter sound
// this is due to this sound playing after the logout message is written so it comes way to late. Enter sound is put directly in the logout code to avoid this
// And it looks better if user is automatically logged out instead of having to press enter
if (menuSelection != 6)
{
Sound.PlaySound("enterSound.wav");
}
// Method that calls a method to perform the action based on the selected option
// Returns false when user chooses option "Log out" this exits the menu loop and goes back to the login screen
isLoggedIn = HandleMenuSelection(context, menuSelection, userName);
MenuFunctions.footer();
// Same as above if-statement but doesn't prompt for enter after the method and logs out directly if logout was selected
if (menuSelection != 6)
{
//Sound.PlaySound("enterSound.wav");
// Promts user to press enter key to go back to menu - doesn't accept any other input
MenuFunctions.PressEnter("\t\tPress [Enter] to go to main menu");
}
}
}
}
}
// Handles which method to go to depending on the chosen option
private static bool HandleMenuSelection(BankContext context, int selection, string userName)
{
switch (selection)
{
case 0:
Console.Clear();
ViewAccountInfo(context, userName);
break;
case 1:
TransferMoney(context, userName);
break;
case 2:
WithdrawMoney(context, userName);
break;
case 3:
DepositMoney(context, userName);
break;
case 4:
OpenNewAccount(context, userName);
break;
case 5:
ChangePin(context, userName);
break;
case 6:
// LOGOUT
Sound.PlaySound("enterSound.wav");
MenuFunctions.PrintSuperFastNoNewLine("\t\tYou are now logging out.");
Thread.Sleep(500);
Console.Write(".");
Thread.Sleep(320);
Console.Write(".");
Thread.Sleep(700);
Console.WriteLine();
return false;
default:
Console.WriteLine("Error! Please try again.");
break;
}
return true;
}
// MENU METHODS
// VIEW ACCOUNTS
//private static void DisplayAccountBalances(BankContext context, string userName)
private static void ViewAccountInfo(BankContext context, string userName)
{
//Get info about user from database
User user = DbHelpers.GetUserAndAccounts(context, userName);
//Display user accounts and balance
if (user != null)
{
MenuFunctions.header();
Console.WriteLine($"\t\tUser: {user.Name}\n");
Console.WriteLine("\t\tYour accounts and balance:");
MenuFunctions.footer();
foreach (var account in user.Accounts)
{
//for every account of the user this displays the account name, balance and currency
Console.WriteLine($"\t\t{account.Name}: {Math.Round(account.Balance, 2)} {account.Currency}");
}
}
else
{
Console.WriteLine("\t\tUser not found");
}
}
// TRANSFER
private static void TransferMoney(BankContext context, string userName)
{
// Retrieve the user information, including accounts
User user = DbHelpers.GetUserAndAccounts(context, userName);
// Checks if the user exists
if (user == null)
{
Console.WriteLine("\t\tUser not found. Transfer canceled.");
Thread.Sleep(1000); // Wait to allow the user to read the error message
return;
}
// Allows the user to select an account using arrow keys and highlight the selection
MenuFunctions.header();
int sourceAccountPosition = MenuFunctions.OptionsNavigation(user.Accounts.Select(a => $"\t\t{a.Name}: {Math.Round(a.Balance, 2)} {a.Currency}").ToArray(),
"\t\tSelect the source account to transfer money from:");
// Check if the selected account position is valid
if (sourceAccountPosition < 0 || sourceAccountPosition >= user.Accounts.Count)
{
Console.WriteLine("\t\tInvalid source account selection. Transfer canceled.");
Console.WriteLine("\t\tPress [Enter] to return to the main menu");
MenuFunctions.CursorReadLine();
return;
}
// Makes a list of user accounts
List<Account> userAccountsList = user.Accounts.ToList();
Account sourceAccount = userAccountsList[sourceAccountPosition];
// Retrieve all users except the current user
List<User> otherUsers = context.Users?.Where(u => u.Id != user.Id)?.ToList();
// Display a list of other users for the destination, including the current user
int destinationUserPosition = MenuFunctions.OptionsNavigation(
(otherUsers.Select(u => $"\t\t{u.Name}").ToList()
.Concat(new List<string> { $"\t\t{user.Name} (yourself)" })).ToArray(),
"\t\tSelect the user to transfer money to:");
// Check if the selected destination user position is valid
if (destinationUserPosition < 0 || destinationUserPosition >= otherUsers.Count + 1)
{
Console.WriteLine("\t\tInvalid destination user selection. Transfer canceled.");
Console.WriteLine("\t\tPress [Enter] to return to the main menu");
MenuFunctions.CursorReadLine();
return;
}
User destinationUser = destinationUserPosition < otherUsers.Count
? otherUsers[destinationUserPosition]
: user;
List<Account> destinationAccounts;
// If the destination user is the same as the source user, allow transfer between own accounts (
if (destinationUser.Id == user.Id)
{
destinationAccounts = userAccountsList.Where(a => a.Id != sourceAccount.Id).ToList();
}
else
{
// Retrieve the destination user's accounts (receiver)
destinationAccounts = context.Accounts
.Where(a => a.UserId == destinationUser.Id)
.ToList();
}
// Check if the destination user actually has accounts
if (destinationAccounts == null || destinationAccounts.Count == 0)
{
Console.WriteLine("\t\tSelected destination user has no accounts. Transfer canceled.");
Console.WriteLine("\t\tPress [Enter] to return to the main menu");
MenuFunctions.CursorReadLine();
return;
}
// Display a list of destination accounts for the selected user
int destinationAccountPosition = MenuFunctions.OptionsNavigation(destinationAccounts
.Select(a => $"\t\t{a.Name}: {Math.Round(a.Balance, 2)} {a.Currency}").ToArray(),
"\t\tSelect the destination account to transfer money to:");
// Check if the selected destination account position is valid
if (destinationAccountPosition < 0 || destinationAccountPosition >= destinationAccounts.Count)
{
Console.WriteLine("\t\tInvalid destination account selection. Transfer canceled.");
Console.WriteLine("\t\tPress [Enter] to return to the main menu");
MenuFunctions.CursorReadLine();
return;
}
Account destinationAccount = destinationAccounts[destinationAccountPosition];
// Prompts the user to enter the amount they want to transfer
Console.Write("\t\tEnter the transfer amount: ");
if (double.TryParse(MenuFunctions.CursorReadLine(), out double transferAmount) && transferAmount > 0)
{
if (sourceAccount.Balance >= transferAmount)
{
if (sourceAccount.Currency != destinationAccount.Currency)
{
double convertedAmount = CurrencyConverter.Convert(sourceAccount.Currency, destinationAccount.Currency, transferAmount);
sourceAccount.Balance -= transferAmount;
destinationAccount.Balance += convertedAmount;
context.SaveChanges();
DisplayBalances(sourceAccount, destinationAccount);
// Play sound after a successful money transfer
Sound.PlaySound("swish.wav");
}
else
{
sourceAccount.Balance -= transferAmount;
destinationAccount.Balance += transferAmount;
context.SaveChanges();
DisplayBalances(sourceAccount, destinationAccount);
// Play sound after a successful money transfer
Sound.PlaySound("swish.wav");
}
}
else
{
Console.WriteLine("\t\tInsufficient funds in the source account. Transfer canceled.");
}
}
else
{
Console.WriteLine("\t\tInvalid transfer amount. Please enter a valid positive number.");
}
// Method to print out new balances
void DisplayBalances(Account source, Account destination)
{
MenuFunctions.footer();
Console.WriteLine($"\t\tTransfer successful!");
Console.WriteLine($"\t\tNew balance for {source.Name}: {Math.Round(source.Balance, 2)} ({source.Currency})");
Console.WriteLine($"\t\tNew balance for {destination.Name}: {Math.Round(destination.Balance, 2)} ({destination.Currency})");
}
}
// WITHDRAW
private static void WithdrawMoney(BankContext context, string userName)
{
// Prompt the user for their PIN
Console.Write("\t\t\tPIN: ");
string customerPin = HidePin.EnterPin();;
Console.WriteLine();
while (true)
{
// Check if the provided PIN is valid for the given user
if (DbHelpers.VerifyUserLogin(context, userName, customerPin))
{
// Retrieve the user information, including accounts
User user = DbHelpers.GetUserAndAccounts(context, userName);
// Check if the user exists
if (user == null)
{
Console.WriteLine("\t\tUser not found. Withdraw canceled.");
Console.ReadKey(true);
return;
}
// Allows the user to select an account using arrow keys and highlight the selection
int chosenAccountPosition = MenuFunctions.OptionsNavigation(user.Accounts.Select(a => $"\t\t{a.Name}: {Math.Round(a.Balance,2)} {a.Currency}").ToArray(), "\t\tChoose account to withdraw:");
// Check if the selected account position is valid
if (chosenAccountPosition < 0 || chosenAccountPosition >= user.Accounts.Count)
{
Console.WriteLine("\t\tInvalid account selection. Withdrawal canceled.");
Console.ReadKey(true);
return;
}
//Retrieves the selected account
Account selectedAccount = user.Accounts.ElementAt(chosenAccountPosition);
// Prompt the user for the withdrawal amount
MenuFunctions.footer();
Console.Write("\t\tHow much would you like to withdraw? ");
// Validates and processes the withdrawal amount
if (double.TryParse(MenuFunctions.CursorReadLine(), out double withdraw))
{
Console.SetCursorPosition(0, Console.CursorTop - 1);
MenuFunctions.ClearCurrentConsoleLine();
double balance = selectedAccount.Balance;
// Check if the withdrawal amount is valid
if (withdraw > balance)
{
Console.WriteLine($"\t\tCannot withdraw more than: {Math.Round(balance,2)} {selectedAccount.Currency}");
}
if (withdraw <= 0)
{
Console.WriteLine("\t\tCannot withdraw 0 or less");
}
// Update the account balance after the withdrawal and save changes to the database
double newBalance = balance - withdraw;
selectedAccount.Balance = newBalance;
context.SaveChanges();
// Display the new account balance to the user
Console.WriteLine($"\t\tYour new balance is: {Math.Round(newBalance,2)} {selectedAccount.Currency}");
return;
}
else
{
Console.WriteLine("\t\tPlease write a valid number.");
}
}
else
{
Console.WriteLine("\t\tInvalid PIN. Try again.");
return;
}
}
}
// Deposit money to account
private static void DepositMoney(BankContext context, string username)
{
// Retrieve the user information, including accounts
User user = DbHelpers.GetUserAndAccounts(context, username);
// Check if the user exists
if (user.Accounts == null)
{
Console.WriteLine("\t\tAccount not found. Creating new account.");
OpenNewAccount(context, username);
}
else
{
// Display the user's accounts and prompt for a selection
string[] accountOptions = user.Accounts.Select(a => $"\t\t{a.Name}: {Math.Round(a.Balance,2)} {a.Currency}").ToArray();
int chosenAccountPosition = MenuFunctions.OptionsNavigation(accountOptions, "\t\tChoose an account to deposit into:");
// Validates the selected account
if (chosenAccountPosition < 0 || chosenAccountPosition >= user.Accounts.Count)
{
Console.WriteLine("\t\tInvalid account selection. Deposit canceled.");
Console.ReadKey(true);
return;
}
// Retrieve the selected account
Account selectedAccount = user.Accounts.ElementAt(chosenAccountPosition);
MenuFunctions.divider();
// Prompt the user for the deposit amount
Console.Write("\t\tHow much do you wish to deposit? ");
if (double.TryParse(MenuFunctions.CursorReadLine(), out double depositAmount))
{
if (depositAmount > 0)
{
// Perform the deposit operation
MenuFunctions.divider();
Console.WriteLine($"\t\tDepositing {depositAmount} into {selectedAccount.Name}");
selectedAccount.Balance += depositAmount;
context.SaveChanges();
Console.WriteLine($"\t\tNew balance: {selectedAccount.Balance}");
}
else if (depositAmount < 0)
{
// Handle invalid negative amount input
Console.WriteLine("\t\tCan't deposit a negative amount.");
}
else
{
Console.WriteLine("\t\tInvalid amount entered!");
}
}
}
}
// OPEN NEW ACCOUNT
// Create a new account for logged in user
private static void OpenNewAccount(BankContext context, string userName)
{
// Clear window
Console.Clear();
// Declare new account variable outside of loop
string newAccountName;
while (true)
{
MenuFunctions.header();
Console.Write("\t\tEnter new account name: ");
newAccountName = MenuFunctions.CursorReadLine();
// Checks if string is null or empty or if an account with that name already exist for current user
if (string.IsNullOrEmpty(newAccountName))
{
Console.WriteLine("\t\tError! Name cannot be empty. \n");
}
else if (DbHelpers.AccountAlreadyExist(context, userName, newAccountName))
{
Console.WriteLine("\t\tError! You already have an account with that name. \n");
}
else
break;
}
// Set Swedish Krona (SEK) as the default currency
string selectedCurrency = "SEK";
// Declare array navOptions as yes or no
string[] navOptions = { "\t\tYes", "\t\tNo" };
// Passes along the options yes and no as well as the phrase to the nav method
// Checks if it returns 0 (which translates to yes in this case) and runs the code, otherwise skips.
if (MenuFunctions.OptionsNavigation(navOptions, "\t\tWill this account be in a foreign currency?") == 0)
{
// Create array of all the currenies to choose from
string[] currencyOptions = {
"\t\tUS Dollar (USD)", "\t\tEuro (EUR)", "\t\tUK Sterling (GBP)", "\t\tSwiss Franc (CHF)",
"\t\tCanadian Dollar (CAD)", "\t\tZimbabwean Dollar (ZWD)"
// ADD MORE CURRENCIES HERE
};
// Create array of available currency shortname
string[] currencies = { "USD", "EUR", "GBP", "CHF", "CAD", "ZWD" };
// Prompts user to choose one of the foreign
int chosenOption = MenuFunctions.OptionsNavigation(currencyOptions, "\t\tAvailable foreign currencies: ");
// Sets selectedCurrency to the chopsen one from the aboce OptionsNavigation
selectedCurrency = currencies[chosenOption];
}
// Creates new user object of the user that's logged in
User user = DbHelpers.GetUser(context, userName);
// Creates a new account object on the logged in user with the chosen name and currency (SEK unless it's foreign account) with a starting balance of 0
Account account = new Account()
{
UserId = user.Id,
Name = newAccountName,
Balance = 0,
Currency = selectedCurrency
};
// Passes along the options yes and no as well as the phrase to the nav method
// Checks if it returns 0 (which translates to yes in this case) and runs the code, otherwise skips.
if (MenuFunctions.OptionsNavigation(navOptions, $"\t\tDo you wish make a deposit to {newAccountName}?") == 0)
{
// Re-promts user until correct input is made
while (true)
{
Console.Clear();
MenuFunctions.header();
// Asks user for deposit amount and checks if value is correct. If yes changes account balance to chosen amount and breaks out of the loop to continue with the rest of the code.
Console.Write($"\t\tEnter deposit amount in {selectedCurrency}: ");
if (double.TryParse(MenuFunctions.CursorReadLine(), out double initialDeposit) && initialDeposit >= 0)
{
account.Balance = initialDeposit;
break;
}
else
{
Console.WriteLine("\t\tInvalid deposit amount. Please enter a valid positive number.");
}
}
}
// Attempts to add account to database. Returns true or false if successful or not
bool success = DbHelpers.AddAccount(context, account);
if (success)
{
Console.WriteLine($"\t\tCreated new account '{newAccountName}' for user '{userName}'");
}
else
{
Console.WriteLine($"\t\tFailed to create account '{newAccountName}'");
Console.WriteLine("\t\tReturning to menu");
return;
}
Console.WriteLine(); // New line for text formatting
}
// CHANGE PIN
// Changes current pin to a new pin for a user
private static void ChangePin(BankContext context, string username)
{
User user = DbHelpers.GetUser(context, username);
// Asks user for pin and checks if it matches login
while (true)
{
// Clear screen and re-print header
Console.Clear();
MenuFunctions.header();
Console.Write("\t\tEnter current PIN: ");
string currentPin = HidePin.EnterPin();
// Re-promt user until string isn't empty
while (string.IsNullOrEmpty(currentPin))
{
Console.Write("\t\tError! PIN can't be empty");
Thread.Sleep(1000);
// Clear screen and re-print header
Console.Clear();
MenuFunctions.header();
Console.Write("\t\tEnter current PIN: ");
currentPin = HidePin.EnterPin();
}
// If pin matches login info, break out of loop
if (DbHelpers.VerifyUserLogin(context, username, currentPin))
break;
else
Console.WriteLine("\t\tError! Wrong PIN. Try again. \n");
Thread.Sleep(1000);
}
// Re-promt user for pins until 2 consecutive pins match
while (true)
{
// Clear screen and re-print header
Console.Clear();
MenuFunctions.header();
Console.Write("\t\tEnter new 4 digit PIN: ");
string newPin = HidePin.EnterPin();
Console.Write("\t\tConfirm new PIN: ");
string newPinConfirm = HidePin.EnterPin();
// Checks so either pin is not null or empty
if (!string.IsNullOrEmpty(newPin) || !string.IsNullOrEmpty(newPinConfirm))
{
// Checks so both pins are only digits
if (newPin.All(char.IsDigit) || newPinConfirm.All(char.IsDigit))
{
// Checks if both pins are exactly 4 digits long
if (newPin.Length == 4 && newPinConfirm.Length == 4)
{
// If pins match save them to database and break out of loop - else write error message
if (newPin == newPinConfirm)
{
bool success = DbHelpers.EditPin(context, user, newPin);
if (success)
{
Console.WriteLine($"\t\tChanged PIN for user {username}");
Thread.Sleep(1500);
}
// If wasn't possible to save account to database, print error
else
{
Console.WriteLine($"\t\tFailed to update PIN for {username}");
Console.WriteLine("\t\tReturning to menu");
Thread.Sleep(1500);
}
break;
}
else
Console.WriteLine("\t\tPIN codes doesn't match.");
}
else
Console.WriteLine("\t\tPIN must be exactly 4 digits.");
}
else
Console.WriteLine("\t\tError! PIN can only contain digits.");
}
else
Console.WriteLine("\t\tError! PIN can't be empty.");
Thread.Sleep(1000);
}
}
}
}