diff --git a/CodingTracker/CodingTracker.sln b/CodingTracker/CodingTracker.sln
new file mode 100644
index 00000000..0fef2785
--- /dev/null
+++ b/CodingTracker/CodingTracker.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.12.35707.178 d17.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodingTracker", "CodingTracker\CodingTracker.csproj", "{03120830-35AE-49F7-AC34-1EDC2B3F8ACF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {03120830-35AE-49F7-AC34-1EDC2B3F8ACF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {03120830-35AE-49F7-AC34-1EDC2B3F8ACF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {03120830-35AE-49F7-AC34-1EDC2B3F8ACF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {03120830-35AE-49F7-AC34-1EDC2B3F8ACF}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/CodingTracker/CodingTracker/App.config b/CodingTracker/CodingTracker/App.config
new file mode 100644
index 00000000..71516352
--- /dev/null
+++ b/CodingTracker/CodingTracker/App.config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/CodingTracker/CodingTracker/CodingTracker.csproj b/CodingTracker/CodingTracker/CodingTracker.csproj
new file mode 100644
index 00000000..ffff1342
--- /dev/null
+++ b/CodingTracker/CodingTracker/CodingTracker.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
diff --git a/CodingTracker/CodingTracker/CodingTracker.db b/CodingTracker/CodingTracker/CodingTracker.db
new file mode 100644
index 00000000..db8c178b
Binary files /dev/null and b/CodingTracker/CodingTracker/CodingTracker.db differ
diff --git a/CodingTracker/CodingTracker/Controllers/CodingSessionController.cs b/CodingTracker/CodingTracker/Controllers/CodingSessionController.cs
new file mode 100644
index 00000000..cb2afe27
--- /dev/null
+++ b/CodingTracker/CodingTracker/Controllers/CodingSessionController.cs
@@ -0,0 +1,101 @@
+using CodingTracker.Models;
+using Dapper;
+using Microsoft.Data.Sqlite;
+using System.Configuration;
+
+namespace CodingTracker.Controllers;
+
+internal class CodingSessionController
+{
+ protected readonly string _connectionString = ConfigurationManager.AppSettings.Get("Connectionstring") ?? throw new Exception("Key value pair doesn't exist in the config-file!");
+
+ public List GetAll()
+ {
+ using (var connection = new SqliteConnection(_connectionString))
+ {
+ string query = "SELECT * FROM CodingSession";
+
+ connection.Open();
+
+ return connection.Query(query).ToList();
+ }
+ }
+
+ public CodingSession GetById(int id)
+ {
+ using (var connection = new SqliteConnection(_connectionString))
+ {
+ string query = "SELECT * FROM CodingSession WHERE Id = @Id";
+
+ connection.Open();
+
+ return connection.Query(query, new { Id = id }).First();
+ }
+ }
+
+ ///
+ /// Returns the number of rows affected
+ ///
+ ///
+ ///
+ public int Add(CodingSession codingSession)
+ {
+ using (var connection = new SqliteConnection(_connectionString))
+ {
+ string sql = "INSERT INTO CodingSession (StartTime, EndTime, Duration) VALUES (@StartTime, @EndTime, @Duration)";
+
+ connection.Open();
+
+ return connection.Execute(sql, codingSession);
+ }
+ }
+
+ ///
+ /// Returns the number of rows affected
+ ///
+ ///
+ ///
+ public int Update(CodingSession codingSession)
+ {
+ using (var connection = new SqliteConnection(_connectionString))
+ {
+ string sql = "UPDATE CodingSession SET StartTime = @StartTime, EndTime = @EndTime, Duration = @Duration WHERE id = @Id";
+
+ connection.Open();
+
+ return connection.Execute(sql, codingSession);
+ }
+ }
+
+ ///
+ /// Returns the number of rows affected
+ ///
+ ///
+ ///
+ public int Delete(int id)
+ {
+ using (var connection = new SqliteConnection(_connectionString))
+ {
+ string sql = "DELETE FROM CodingSession WHERE id = @Id";
+
+ connection.Open();
+
+ return connection.Execute(sql, new { Id = id});
+ }
+ }
+
+ internal bool Exists(int id)
+ {
+ using (var connection = new SqliteConnection(_connectionString))
+ {
+ string sql = "SELECT * FROM CodingSession WHERE id = @Id";
+
+ connection.Open();
+
+ var reader = connection.ExecuteScalar(sql, new { Id = id });
+
+ return reader != null;
+ }
+
+ }
+}
diff --git a/CodingTracker/CodingTracker/Database.cs b/CodingTracker/CodingTracker/Database.cs
new file mode 100644
index 00000000..d72b8188
--- /dev/null
+++ b/CodingTracker/CodingTracker/Database.cs
@@ -0,0 +1,35 @@
+using Microsoft.Data.Sqlite;
+using System.Configuration;
+
+namespace CodingTracker;
+
+internal static class Database
+{
+ private static readonly string _connectionString = ConfigurationManager.AppSettings.Get("Connectionstring") ??
+ throw new Exception("Key value pair doesn't exist in the config-file!");
+
+ private static readonly string _databasePath = ConfigurationManager.AppSettings.Get("DatabasePath") ??
+ throw new Exception("Key value pair doesn't exist in the config-file!");
+ internal static void CreateDatabase()
+ {
+ if (!File.Exists(_databasePath))
+ {
+ using (SqliteConnection connection = new SqliteConnection(_connectionString))
+ {
+ connection.Open();
+
+ var command = connection.CreateCommand();
+ command.CommandText =
+ @"CREATE TABLE CodingSession
+ (
+ Id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ StartTime TEXT NOT NULL,
+ EndTime TEXT NOT NULL,
+ Duration INTEGER NOT NULL
+ )";
+
+ command.ExecuteNonQuery();
+ }
+ }
+ }
+}
diff --git a/CodingTracker/CodingTracker/Enums/MenuItems.cs b/CodingTracker/CodingTracker/Enums/MenuItems.cs
new file mode 100644
index 00000000..390b4577
--- /dev/null
+++ b/CodingTracker/CodingTracker/Enums/MenuItems.cs
@@ -0,0 +1,11 @@
+namespace CodingTracker.Enums;
+
+internal enum MenuItems
+{
+ StartCodingSession,
+ ViewAll,
+ Add,
+ Update,
+ Delete,
+ Quit
+}
diff --git a/CodingTracker/CodingTracker/Models/CodingSession.cs b/CodingTracker/CodingTracker/Models/CodingSession.cs
new file mode 100644
index 00000000..50c6e9ff
--- /dev/null
+++ b/CodingTracker/CodingTracker/Models/CodingSession.cs
@@ -0,0 +1,9 @@
+namespace CodingTracker.Models;
+
+internal class CodingSession
+{
+ public int Id { get; set; }
+ public DateTime StartTime { get; set; }
+ public DateTime EndTime { get; set; }
+ public double Duration { get; set; }
+}
diff --git a/CodingTracker/CodingTracker/Program.cs b/CodingTracker/CodingTracker/Program.cs
new file mode 100644
index 00000000..9ea0ee5b
--- /dev/null
+++ b/CodingTracker/CodingTracker/Program.cs
@@ -0,0 +1,7 @@
+using CodingTracker;
+using CodingTracker.UserInterface;
+
+Database.CreateDatabase();
+
+UserMenu userMenu = new UserMenu();
+userMenu.ShowMenu();
diff --git a/CodingTracker/CodingTracker/Properties/launchSettings.json b/CodingTracker/CodingTracker/Properties/launchSettings.json
new file mode 100644
index 00000000..09130bf4
--- /dev/null
+++ b/CodingTracker/CodingTracker/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "CodingTracker": {
+ "commandName": "Project",
+ "workingDirectory": "C:\\Users\\gilles.lagrilliere\\OneDrive - Codraft\\Documents\\C#-projects\\CodeReviews.Console.CodingTracker\\CodingTracker\\CodingTracker"
+ }
+ }
+}
\ No newline at end of file
diff --git a/CodingTracker/CodingTracker/UserInterface/UserInput.cs b/CodingTracker/CodingTracker/UserInterface/UserInput.cs
new file mode 100644
index 00000000..79d40441
--- /dev/null
+++ b/CodingTracker/CodingTracker/UserInterface/UserInput.cs
@@ -0,0 +1,159 @@
+using CodingTracker.Controllers;
+using CodingTracker.Models;
+using Spectre.Console;
+using System.Diagnostics;
+
+namespace CodingTracker.UserInterface;
+
+internal static class UserInput
+{
+ private static readonly CodingSessionController _controller = new CodingSessionController();
+ public static void ViewAll()
+ {
+ var AllCodingSessions = _controller.GetAll();
+
+ PrintCodingSessions(AllCodingSessions);
+
+ Console.WriteLine("Press any key to continue");
+ Console.ReadKey();
+ }
+
+ public static void Add()
+ {
+ var session = AskForInput();
+
+ _controller.Add(session);
+ }
+
+ public static void Update()
+ {
+ var AllCodingSessions = _controller.GetAll();
+
+ PrintCodingSessions(AllCodingSessions);
+
+ int id;
+ do
+ {
+ id = AnsiConsole.Ask("Choose the [yellow]Id[/] of a session to update.");
+ }
+ while (!_controller.Exists(id));
+
+ var session = AskForInput();
+ session.Id = id;
+
+ _controller.Update(session);
+ }
+
+ public static void Delete()
+ {
+ var AllCodingSessions = _controller.GetAll();
+
+ PrintCodingSessions(AllCodingSessions);
+ int id;
+
+ do
+ {
+ id = AnsiConsole.Ask("Choose a valid [yellow]Id[/] of a session to delete.");
+ }
+ while (!_controller.Exists(id));
+
+ _controller.Delete(id);
+ }
+
+ public static void StartCodingSession()
+ {
+ Console.WriteLine("press any key to start the session");
+ Console.ReadKey(true);
+
+ Stopwatch stopwatch = Stopwatch.StartNew();
+ stopwatch.Start();
+
+ var startTime = DateTime.Now;
+ startTime = new DateTime(
+ startTime.Ticks - (startTime.Ticks % TimeSpan.TicksPerSecond),
+ startTime.Kind
+ );
+
+ Console.WriteLine("press enter to stop the session");
+
+ ConsoleKeyInfo input;
+ do
+ {
+ input = Console.ReadKey();
+ }
+ while (input.Key is not ConsoleKey.Enter);
+
+ stopwatch.Stop();
+ var endTime = DateTime.Now;
+ endTime = new DateTime(
+ endTime.Ticks - (endTime.Ticks % TimeSpan.TicksPerSecond),
+ endTime.Kind
+ );
+
+ var duration = new TimeSpan(stopwatch.Elapsed.Ticks / TimeSpan.TicksPerSecond * TimeSpan.TicksPerSecond); //truncate the milliseconds
+
+ string elapsedTime = $"{duration.Hours:00}:{duration.Minutes:00}:{duration.Seconds:00}";
+ Console.WriteLine("Codingtime: " + elapsedTime);
+ Console.ReadKey();
+
+ var session = new CodingSession()
+ {
+ StartTime = startTime,
+ EndTime = endTime,
+ Duration = duration.TotalSeconds
+ };
+
+ _controller.Add(session);
+ }
+
+ private static string ConvertDateToString(DateTime date)
+ {
+ return date.ToString("dd-MM-yyyy HH:mm");
+ }
+
+ private static string ConvertTimeSpanToString(double duration)
+ {
+ return TimeSpan.FromSeconds(duration).ToString();
+ }
+
+ private static void PrintCodingSessions(List sessions)
+ {
+ var table = new Table();
+ table.AddColumns("Id", "StartTime", "EndTime", "Duration");
+
+ foreach (var session in sessions)
+ {
+ var startTime = ConvertDateToString(session.StartTime);
+ var endTime = ConvertDateToString(session.EndTime);
+ var duration = ConvertTimeSpanToString(session.Duration);
+
+ table.AddRow([session.Id.ToString(), startTime, endTime, duration]);
+ }
+
+ AnsiConsole.Write(table);
+ }
+
+ private static CodingSession AskForInput()
+ {
+ var startTime = AnsiConsole.Ask("What time did you start(mm-dd-yyyy hh:mm): ");
+ var endTime = AnsiConsole.Ask("What time did you end(mm-dd-yyyy hh:mm): ");
+ while (DateTime.Compare(startTime, endTime) > 0)
+ {
+ Console.WriteLine("EndTime can not be before the starttime.");
+ endTime = AnsiConsole.Ask("What time did you end(mm-dd-yyyy hh:mm): ");
+ }
+
+ var duration = endTime - startTime;
+
+ CodingSession session = new CodingSession()
+ {
+ StartTime = startTime,
+ EndTime = endTime,
+ Duration = duration.TotalSeconds
+ };
+
+ return session;
+ }
+
+
+}
diff --git a/CodingTracker/CodingTracker/UserInterface/UserMenu.cs b/CodingTracker/CodingTracker/UserInterface/UserMenu.cs
new file mode 100644
index 00000000..0dcd2917
--- /dev/null
+++ b/CodingTracker/CodingTracker/UserInterface/UserMenu.cs
@@ -0,0 +1,62 @@
+using CodingTracker.Controllers;
+using CodingTracker.Enums;
+using Spectre.Console;
+
+namespace CodingTracker.UserInterface;
+
+internal class UserMenu
+{
+ private CodingSessionController _controller = new CodingSessionController();
+ public void ShowMenu()
+ {
+ while (true)
+ {
+ Console.Clear();
+
+ var choice = AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("Pick an option")
+ .AddChoices(Enum.GetValues()));
+
+ switch (choice)
+ {
+ case MenuItems.StartCodingSession:
+ ClearConsole();
+ UserInput.StartCodingSession();
+ break;
+
+ case MenuItems.ViewAll:
+ ClearConsole();
+ UserInput.ViewAll();
+ break;
+
+ case MenuItems.Add:
+ ClearConsole();
+ UserInput.Add();
+ break;
+
+ case MenuItems.Update:
+ ClearConsole();
+ UserInput.Update();
+ break;
+
+ case MenuItems.Delete:
+ ClearConsole();
+ UserInput.Delete();
+ break;
+
+ case MenuItems.Quit:
+ Environment.Exit(0);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ private void ClearConsole()
+ {
+ Console.Clear();
+ }
+}