Adding extra section in appts screen to show details better, added appt notif on login.

All it needs now is the records sections
This commit is contained in:
Spudnut2000 2025-06-25 22:49:08 -05:00
parent 57359a6260
commit 1434e867bd
13 changed files with 1166 additions and 918 deletions

View File

@ -79,7 +79,6 @@ public partial class AddOrUpdateAppointmentForm : Form
private bool ValidateForm() private bool ValidateForm()
{ {
// Ensure all required fields have values
if (string.IsNullOrWhiteSpace(titleTextBox.Text) || if (string.IsNullOrWhiteSpace(titleTextBox.Text) ||
string.IsNullOrWhiteSpace(descriptionTextBox.Text) || string.IsNullOrWhiteSpace(descriptionTextBox.Text) ||
string.IsNullOrWhiteSpace(locationTextBox.Text) || string.IsNullOrWhiteSpace(locationTextBox.Text) ||
@ -92,18 +91,15 @@ public partial class AddOrUpdateAppointmentForm : Form
return false; return false;
} }
// Convert start and end times to UTC for comparison
DateTime start = startPickerDate.Value.Date.Add(startPickerTime.Value.TimeOfDay).ToUniversalTime(); DateTime start = startPickerDate.Value.Date.Add(startPickerTime.Value.TimeOfDay).ToUniversalTime();
DateTime end = endPickerDate.Value.Date.Add(endPickerTime.Value.TimeOfDay).ToUniversalTime(); DateTime end = endPickerDate.Value.Date.Add(endPickerTime.Value.TimeOfDay).ToUniversalTime();
// Validate start and end times
if (start >= end) if (start >= end)
{ {
MessageBox.Show("Start time must be before end time.", "Validation Error", MessageBoxButtons.OK, MessageBoxIcon.Error); MessageBox.Show("Start time must be before end time.", "Validation Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false; return false;
} }
// Validate business hours (9:00 AM - 5:00 PM EST, Monday-Friday)
TimeZoneInfo estZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); TimeZoneInfo estZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime startEST = TimeZoneInfo.ConvertTimeFromUtc(start, estZone); DateTime startEST = TimeZoneInfo.ConvertTimeFromUtc(start, estZone);
DateTime endEST = TimeZoneInfo.ConvertTimeFromUtc(end, estZone); DateTime endEST = TimeZoneInfo.ConvertTimeFromUtc(end, estZone);
@ -114,7 +110,6 @@ public partial class AddOrUpdateAppointmentForm : Form
return false; return false;
} }
// Check for overlapping appointments
var appointments = DatabaseHelper.RetrieveAppointments(AppState.CurrentUser.UserId); var appointments = DatabaseHelper.RetrieveAppointments(AppState.CurrentUser.UserId);
foreach (var appt in appointments) foreach (var appt in appointments)
{ {
@ -138,7 +133,6 @@ public partial class AddOrUpdateAppointmentForm : Form
try try
{ {
// Gather appointment data from form
var selectedCustomer = (Customer)customerComboBox.SelectedItem!; var selectedCustomer = (Customer)customerComboBox.SelectedItem!;
var appointment = new Appointment var appointment = new Appointment
{ {
@ -161,13 +155,11 @@ public partial class AddOrUpdateAppointmentForm : Form
if (_currentAppointment == null) if (_currentAppointment == null)
{ {
// Add new appointment
DatabaseHelper.AddAppointment(appointment); DatabaseHelper.AddAppointment(appointment);
MessageBox.Show("Appointment added successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); MessageBox.Show("Appointment added successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
} }
else else
{ {
// Update existing appointment
DatabaseHelper.UpdateAppointment(appointment); DatabaseHelper.UpdateAppointment(appointment);
MessageBox.Show("Appointment updated successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); MessageBox.Show("Appointment updated successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
} }

View File

@ -37,7 +37,14 @@ partial class AppointmentsForm
modifyButton = new System.Windows.Forms.Button(); modifyButton = new System.Windows.Forms.Button();
deleteButton = new System.Windows.Forms.Button(); deleteButton = new System.Windows.Forms.Button();
showAllButton = new System.Windows.Forms.Button(); showAllButton = new System.Windows.Forms.Button();
appointmentDetails = new System.Windows.Forms.GroupBox();
apptTitleLabel = new System.Windows.Forms.Label();
apptTypeLabel = new System.Windows.Forms.Label();
withLabel = new System.Windows.Forms.Label();
startTimeLabel = new System.Windows.Forms.Label();
endTimeLabel = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)appointmentDataView).BeginInit(); ((System.ComponentModel.ISupportInitialize)appointmentDataView).BeginInit();
appointmentDetails.SuspendLayout();
SuspendLayout(); SuspendLayout();
// //
// appointmentDataView // appointmentDataView
@ -96,11 +103,71 @@ partial class AppointmentsForm
showAllButton.Text = "Show All Appointments"; showAllButton.Text = "Show All Appointments";
showAllButton.UseVisualStyleBackColor = true; showAllButton.UseVisualStyleBackColor = true;
// //
// appointmentDetails
//
appointmentDetails.Controls.Add(endTimeLabel);
appointmentDetails.Controls.Add(startTimeLabel);
appointmentDetails.Controls.Add(withLabel);
appointmentDetails.Controls.Add(apptTypeLabel);
appointmentDetails.Controls.Add(apptTitleLabel);
appointmentDetails.Location = new System.Drawing.Point(773, 214);
appointmentDetails.Name = "appointmentDetails";
appointmentDetails.Size = new System.Drawing.Size(223, 320);
appointmentDetails.TabIndex = 6;
appointmentDetails.TabStop = false;
appointmentDetails.Text = "Details";
//
// apptTitleLabel
//
apptTitleLabel.Location = new System.Drawing.Point(6, 19);
apptTitleLabel.Name = "apptTitleLabel";
apptTitleLabel.Size = new System.Drawing.Size(211, 23);
apptTitleLabel.TabIndex = 0;
apptTitleLabel.Text = "Title: ";
apptTitleLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// apptTypeLabel
//
apptTypeLabel.Location = new System.Drawing.Point(6, 42);
apptTypeLabel.Name = "apptTypeLabel";
apptTypeLabel.Size = new System.Drawing.Size(211, 23);
apptTypeLabel.TabIndex = 1;
apptTypeLabel.Text = "Type: ";
apptTypeLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// withLabel
//
withLabel.Location = new System.Drawing.Point(6, 65);
withLabel.Name = "withLabel";
withLabel.Size = new System.Drawing.Size(211, 23);
withLabel.TabIndex = 2;
withLabel.Text = "With: ";
withLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// startTimeLabel
//
startTimeLabel.Location = new System.Drawing.Point(6, 88);
startTimeLabel.Name = "startTimeLabel";
startTimeLabel.Size = new System.Drawing.Size(211, 23);
startTimeLabel.TabIndex = 3;
startTimeLabel.Text = "Start: ";
startTimeLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// endTimeLabel
//
endTimeLabel.Location = new System.Drawing.Point(6, 111);
endTimeLabel.Name = "endTimeLabel";
endTimeLabel.Size = new System.Drawing.Size(211, 23);
endTimeLabel.TabIndex = 4;
endTimeLabel.Text = "End: ";
endTimeLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// AppointmentsForm // AppointmentsForm
// //
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(1008, 575); ClientSize = new System.Drawing.Size(1008, 575);
Controls.Add(appointmentDetails);
Controls.Add(showAllButton); Controls.Add(showAllButton);
Controls.Add(deleteButton); Controls.Add(deleteButton);
Controls.Add(modifyButton); Controls.Add(modifyButton);
@ -109,9 +176,19 @@ partial class AppointmentsForm
Controls.Add(appointmentDataView); Controls.Add(appointmentDataView);
Text = "AppointmentsForm"; Text = "AppointmentsForm";
((System.ComponentModel.ISupportInitialize)appointmentDataView).EndInit(); ((System.ComponentModel.ISupportInitialize)appointmentDataView).EndInit();
appointmentDetails.ResumeLayout(false);
ResumeLayout(false); ResumeLayout(false);
} }
private System.Windows.Forms.Label apptTypeLabel;
private System.Windows.Forms.Label withLabel;
private System.Windows.Forms.Label startTimeLabel;
private System.Windows.Forms.Label endTimeLabel;
private System.Windows.Forms.Label apptTitleLabel;
private System.Windows.Forms.GroupBox appointmentDetails;
private System.Windows.Forms.Button showAllButton; private System.Windows.Forms.Button showAllButton;
private System.Windows.Forms.DataGridView appointmentDataView; private System.Windows.Forms.DataGridView appointmentDataView;

View File

@ -20,6 +20,8 @@ public partial class AppointmentsForm : Form
deleteButton.Click += DeleteButtonOnClick; deleteButton.Click += DeleteButtonOnClick;
addButton.Click += AddButtonOnClick; addButton.Click += AddButtonOnClick;
modifyButton.Click += ModifyButtonOnClick; modifyButton.Click += ModifyButtonOnClick;
appointmentDataView.SelectionChanged += UpdateAppointmentDetails;
} }
private void ModifyButtonOnClick(object? sender, EventArgs e) private void ModifyButtonOnClick(object? sender, EventArgs e)
@ -74,4 +76,16 @@ public partial class AppointmentsForm : Form
List<Appointment>? selectedAppointments = _appointments.Where(a => a.Start == date).ToList(); List<Appointment>? selectedAppointments = _appointments.Where(a => a.Start == date).ToList();
appointmentDataView.DataSource = selectedAppointments?.Count > 0 ? selectedAppointments : null; appointmentDataView.DataSource = selectedAppointments?.Count > 0 ? selectedAppointments : null;
} }
private void UpdateAppointmentDetails(object? sender, EventArgs e)
{
if (appointmentDataView.CurrentRow?.DataBoundItem is Appointment appointment)
{
apptTitleLabel.Text = $"Title: {appointment.Title}";
apptTypeLabel.Text = $"Type: {appointment.AppointmentType}";
withLabel.Text = $"With: {DatabaseHelper.RetrieveCustomer(appointment.CustomerId)?.CustomerName ?? "Unknown"}";
startTimeLabel.Text = $"Start: {appointment.Start.ToLocalTime():MM/dd/yyyy hh:mm tt} {TimeZoneInfo.Local.Id}";
endTimeLabel.Text = $"End: {appointment.End.ToLocalTime():MM/dd/yyyy hh:mm tt} {TimeZoneInfo.Local.Id}";
}
}
} }

View File

@ -17,7 +17,7 @@
<Compile Update="DashboardForm.cs"> <Compile Update="DashboardForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
<Compile Update="RecordsForm.cs"> <Compile Update="CustomersForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
<Compile Update="AddUpdateCustomerForm.cs"> <Compile Update="AddUpdateCustomerForm.cs">
@ -29,6 +29,9 @@
<Compile Update="AddOrUpdateAppointmentForm.cs"> <Compile Update="AddOrUpdateAppointmentForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
<Compile Update="ReportsForm.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -2,7 +2,7 @@ using System.ComponentModel;
namespace C969Project; namespace C969Project;
partial class RecordsForm partial class CustomersForm
{ {
/// <summary> /// <summary>
/// Required designer variable. /// Required designer variable.

View File

@ -3,12 +3,12 @@ using C969Project.Data.Models;
namespace C969Project; namespace C969Project;
public partial class RecordsForm : Form public partial class CustomersForm : Form
{ {
private List<Customer>? _customers; private List<Customer>? _customers;
private AddUpdateCustomerForm _form = new(); private AddUpdateCustomerForm _form = new();
public RecordsForm() public CustomersForm()
{ {
InitializeComponent(); InitializeComponent();
UpdateCustomersList(null, EventArgs.Empty); UpdateCustomersList(null, EventArgs.Empty);

View File

@ -2,20 +2,20 @@ namespace C969Project;
public partial class DashboardForm : Form public partial class DashboardForm : Form
{ {
private RecordsForm _recordsForm; private CustomersForm _customersForm;
private AppointmentsForm _appointmentsForm; private AppointmentsForm _appointmentsForm;
public DashboardForm() public DashboardForm()
{ {
InitializeComponent(); InitializeComponent();
_recordsForm = new RecordsForm(); _customersForm = new CustomersForm();
_appointmentsForm = new AppointmentsForm(); _appointmentsForm = new AppointmentsForm();
CustomersButton.Click += (sender, args) => CustomersButton.Click += (sender, args) =>
{ {
_recordsForm.ShowDialog(); _customersForm.ShowDialog();
_recordsForm.UpdateCustomersList(null, EventArgs.Empty); _customersForm.UpdateCustomersList(null, EventArgs.Empty);
}; };
AppointmentsButton.Click += (sender, args) => AppointmentsButton.Click += (sender, args) =>

View File

@ -1,10 +1,8 @@
using System;
using System.Data;
using MySql.Data.MySqlClient; using MySql.Data.MySqlClient;
using C969Project.Data.Models; using C969Project.Data.Models;
namespace C969Project.Data namespace C969Project.Data;
{
public static class DatabaseHelper public static class DatabaseHelper
{ {
private static string ConnectionString => AppSettings.GetSetting("ConnectionStrings", "DefaultConnection"); private static string ConnectionString => AppSettings.GetSetting("ConnectionStrings", "DefaultConnection");
@ -18,7 +16,8 @@ namespace C969Project.Data
} }
catch (MySqlException ex) catch (MySqlException ex)
{ {
Console.WriteLine(ex.Message); MessageBox.Show($"Database connection error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
} }
string query = "SELECT * FROM client_schedule.user WHERE userName = @username"; string query = "SELECT * FROM client_schedule.user WHERE userName = @username";
@ -52,8 +51,8 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine(e); MessageBox.Show($"Database connection error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw; return new List<Customer>();
} }
List<Customer> customers = new List<Customer>(); List<Customer> customers = new List<Customer>();
@ -80,6 +79,42 @@ namespace C969Project.Data
return customers; return customers;
} }
public static Customer? RetrieveCustomer(int customerId)
{
using MySqlConnection connection = new MySqlConnection(AppSettings.GetSetting("ConnectionStrings", "DefaultConnection"));
try
{
connection.Open();
}
catch (MySqlException e)
{
MessageBox.Show($"Database connection error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
string query = "SELECT * FROM client_schedule.customer WHERE customerId = @customerId";
using MySqlCommand command = new MySqlCommand(query, connection);
command.Parameters.AddWithValue("@customerId", customerId);
using MySqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
return new Customer
{
CustomerId = reader.GetInt32("customerId"),
CustomerName = reader.GetString("customerName"),
AddressId = reader.GetInt32("addressId"),
Active = reader.GetInt32("active"),
CreateDate = reader.GetDateTime("createDate"),
CreatedBy = reader.GetString("createdBy"),
LastUpdate = reader.GetDateTime("lastUpdate"),
LastUpdateBy = reader.GetString("lastUpdateBy"),
};
}
return null;
}
public static int AddCustomer(Customer customer) public static int AddCustomer(Customer customer)
{ {
int customerId = 0; int customerId = 0;
@ -110,13 +145,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
return customerId; return customerId;
} }
@ -144,13 +177,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -167,13 +198,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -194,8 +223,8 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine(e); MessageBox.Show($"Database connection error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw; return null;
} }
string query = "SELECT * FROM client_schedule.address WHERE addressId = @addressId"; string query = "SELECT * FROM client_schedule.address WHERE addressId = @addressId";
@ -235,8 +264,8 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine(e); MessageBox.Show($"Database connection error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw; return new List<Address>();
} }
List<Address> addresses = new List<Address>(); List<Address> addresses = new List<Address>();
@ -297,13 +326,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
return addressId; return addressId;
} }
@ -333,13 +360,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -356,13 +381,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -384,8 +407,8 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine(e); MessageBox.Show($"Database connection error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw; return null;
} }
string query = "SELECT * FROM client_schedule.appointment WHERE appointmentId = @appointmentId"; string query = "SELECT * FROM client_schedule.appointment WHERE appointmentId = @appointmentId";
@ -430,8 +453,8 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine(e); MessageBox.Show($"Database connection error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw; return new List<Appointment>();
} }
List<Appointment> appointments = new List<Appointment>(); List<Appointment> appointments = new List<Appointment>();
@ -502,13 +525,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -544,13 +565,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -567,13 +586,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -594,8 +611,8 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine(e); MessageBox.Show($"Database connection error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw; return null;
} }
string query = "SELECT * FROM client_schedule.city WHERE cityId = @cityId"; string query = "SELECT * FROM client_schedule.city WHERE cityId = @cityId";
@ -632,8 +649,8 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine(e); MessageBox.Show($"Database connection error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw; return new List<City>();
} }
List<City> cities = new List<City>(); List<City> cities = new List<City>();
@ -682,7 +699,7 @@ namespace C969Project.Data
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Error getting city ID: {ex.Message}"); MessageBox.Show($"Error getting city ID: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
} }
return cityId; return cityId;
} }
@ -716,13 +733,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
return cityId; return cityId;
} }
@ -749,13 +764,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -772,13 +785,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -798,8 +809,8 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine(e); MessageBox.Show($"Database connection error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw; return null;
} }
string query = "SELECT * FROM client_schedule.country WHERE countryId = @countryId"; string query = "SELECT * FROM client_schedule.country WHERE countryId = @countryId";
@ -835,8 +846,8 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine(e); MessageBox.Show($"Database connection error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw; return new List<Country>();
} }
List<Country> countries = new List<Country>(); List<Country> countries = new List<Country>();
@ -883,7 +894,7 @@ namespace C969Project.Data
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Error getting country ID: {ex.Message}"); MessageBox.Show($"Error getting country ID: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
} }
return countryId; return countryId;
} }
@ -916,13 +927,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
return countryId; return countryId;
} }
@ -948,13 +957,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -971,13 +978,11 @@ namespace C969Project.Data
} }
catch (MySqlException e) catch (MySqlException e)
{ {
Console.WriteLine($"MySQL Error: {e.Message}"); MessageBox.Show($"MySQL Error: {e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"General Error: {ex.Message}"); MessageBox.Show($"General Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
throw;
} }
} }
@ -987,4 +992,4 @@ namespace C969Project.Data
} }
#endregion #endregion
} }
}

View File

@ -34,12 +34,44 @@ namespace C969Project
Console.WriteLine($"Login successful, {usr.Username}"); Console.WriteLine($"Login successful, {usr.Username}");
AppState.CurrentUser = usr; AppState.CurrentUser = usr;
CheckForAppointments();
var dash = new DashboardForm(); var dash = new DashboardForm();
dash.FormClosing += (o, args) => { Close(); }; dash.FormClosing += (o, args) => { Close(); };
dash.Show(); dash.Show();
Hide(); Hide();
} }
private void CheckForAppointments()
{
if (AppState.CurrentUser is null)
{
MessageBox.Show("No user logged in, cannot check for appointments.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var appointments = DatabaseHelper.RetrieveAppointments(AppState.CurrentUser.UserId);
DateTime nowUtc = DateTime.UtcNow;
DateTime fifteenMinutesFromNowUtc = nowUtc.AddMinutes(15);
var upcoming = appointments
.Where(a => a.Start >= nowUtc && a.Start <= fifteenMinutesFromNowUtc)
.OrderBy(a => a.Start)
.ToList();
if (upcoming.Any())
{
var appt = upcoming.First();
DateTime localStart = appt.Start.ToLocalTime();
MessageBox.Show(
$"You have an upcoming {appt.AppointmentType} appointment '{appt.Title}' at {localStart}.",
"Upcoming Appointment",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}
private void UpdateLoginButtonState() private void UpdateLoginButtonState()
{ {
if (string.IsNullOrEmpty(usernameTextBox.Text) || string.IsNullOrEmpty(passwordTextBox.Text)) if (string.IsNullOrEmpty(usernameTextBox.Text) || string.IsNullOrEmpty(passwordTextBox.Text))

41
C969Project/ReportsForm.Designer.cs generated Normal file
View File

@ -0,0 +1,41 @@
using System.ComponentModel;
namespace C969Project;
partial class ReportsForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "ReportsForm";
}
#endregion
}

View File

@ -0,0 +1,9 @@
namespace C969Project;
public partial class ReportsForm : Form
{
public ReportsForm()
{
InitializeComponent();
}
}

75
C969Project/todo.md Normal file
View File

@ -0,0 +1,75 @@
# ✅ C# Application Development To-Do List
## 1. Login Form
- [x] Create a login form with the following functionality:
- [x] Determine a users location.
- [x] Translate login and error control messages into:
- [x] English
- [x] One additional language
- [x] Verify correct username and password.
## 2. Customer Record Management
- [x] Add functionality to:
- [x] Add customer records
- [x] Update customer records
- [x] Delete customer records
- [x] Validate customer record requirements:
- [x] Include name, address, and phone number fields.
- [x] Ensure fields are trimmed and non-empty.
- [x] Restrict phone number field to digits and dashes only.
- [x] Add exception handling for:
- [x] Add operations
- [x] Update operations
- [x] Delete operations
## 3. Appointment Management
- [x] Add functionality to:
- [x] Add appointments
- [x] Update appointments
- [x] Delete appointments
- [x] Capture appointment type
- [x] Link each appointment to a specific customer
- [x] Validate appointment requirements:
- [x] Appointments must be during business hours (9:00 a.m. 5:00 p.m., MondayFriday, EST).
- [x] Prevent scheduling of overlapping appointments.
- [x] Add exception handling for:
- [x] Add operations
- [x] Update operations
- [x] Delete operations
## 4. Calendar View
- [x] Implement a calendar view:
- [x] Allow selection of a day of the month
- [x] Display appointments for that specific day
## 5. Time Zone Adjustment
- [x] Automatically adjust appointment times based on:
- [x] User time zones
- [x] Daylight saving time
## 6. Appointment Alerts
- [x] Create a function to:
- [x] Generate an alert when a user with an appointment within 15 minutes logs in
## 7. Reports
- [ ] Create a report generator using collection classes and lambda expressions:
- [ ] Report: Number of appointment types by month
- [ ] Report: Schedule for each user
- [ ] Report: One additional report of your choice
## 8. Login History
- [x] Record each login attempt:
- [x] Include timestamp and username
- [x] Append to “Login_History.txt” file