572 lines
18 KiB
C#
572 lines
18 KiB
C#
using System.IO; // Explicitly included for Path
|
|
using FrymasterBadgeApp.Services;
|
|
using Microsoft.Data.SqlClient;
|
|
using Microsoft.Maui.Controls.Shapes; // For RoundRectangle
|
|
using Microsoft.Maui.Graphics;
|
|
|
|
namespace FrymasterBadgeApp;
|
|
|
|
public partial class EmployeePage : ContentPage
|
|
{
|
|
private readonly SqlService _db;
|
|
private readonly PrinterService _printerService;
|
|
private Dictionary<string, object>? _selectedEmployee;
|
|
private readonly Dictionary<string, object> _currentCompany;
|
|
|
|
private string _tempCapturePath = "";
|
|
private double _editX = 0;
|
|
private double _editY = 0;
|
|
|
|
private string _currentBadgeType = "Office";
|
|
private string _currentGuestImage = "Guest1.png";
|
|
|
|
public EmployeePage(
|
|
SqlService db,
|
|
PrinterService printerService,
|
|
Dictionary<string, object> company
|
|
)
|
|
{
|
|
InitializeComponent();
|
|
_db = db;
|
|
_printerService = printerService;
|
|
_currentCompany = company;
|
|
|
|
EditorPhotoPreview.SetBinding(
|
|
Image.ScaleProperty,
|
|
new Binding("Value", source: ZoomSlider)
|
|
);
|
|
|
|
GuestImagePicker.Items.Add("Guest1.png");
|
|
GuestImagePicker.Items.Add("Guest2.png");
|
|
GuestImagePicker.Items.Add("Guest3.png");
|
|
GuestImagePicker.SelectedIndex = 0;
|
|
GuestImagePicker.SelectedIndexChanged += OnGuestImageChanged;
|
|
|
|
BadgeTypePicker.SelectedIndexChanged += OnBadgeTypeChanged;
|
|
|
|
LoadCompanyLogo();
|
|
LoadEmployees();
|
|
}
|
|
|
|
private string GetPhotoDir()
|
|
{
|
|
string path = @"C:\FrymasterData\photos";
|
|
if (!Directory.Exists(path))
|
|
Directory.CreateDirectory(path);
|
|
return path;
|
|
}
|
|
|
|
private void LoadCompanyLogo()
|
|
{
|
|
string logoPath = _currentCompany.GetValueOrDefault("logo")?.ToString() ?? "";
|
|
if (!string.IsNullOrEmpty(logoPath) && File.Exists(logoPath))
|
|
{
|
|
PreviewLogoFront.Source = ImageSource.FromFile(logoPath);
|
|
}
|
|
}
|
|
|
|
private void LoadEmployees()
|
|
{
|
|
string sql =
|
|
"SELECT *, ISNULL(BadgeType, 'Office') AS BadgeType FROM dbo.tblData ORDER BY Data2";
|
|
var results = _db.Query(sql, null);
|
|
MainThread.BeginInvokeOnMainThread(() => EmployeeList.ItemsSource = results);
|
|
}
|
|
|
|
private void OnSearchTextChanged(object sender, TextChangedEventArgs e)
|
|
{
|
|
string search = $"%{e.NewTextValue}%";
|
|
string sql =
|
|
@"SELECT *, ISNULL(BadgeType, 'Office') AS BadgeType
|
|
FROM dbo.tblData
|
|
WHERE Data2 LIKE @s OR Data1 LIKE @s
|
|
ORDER BY Data2";
|
|
var results = _db.Query(sql, new[] { new SqlParameter("@s", search) });
|
|
MainThread.BeginInvokeOnMainThread(() =>
|
|
{
|
|
EmployeeList.SelectedItem = null;
|
|
EmployeeList.ItemsSource = results;
|
|
});
|
|
}
|
|
|
|
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
{
|
|
_selectedEmployee = e.CurrentSelection.FirstOrDefault() as Dictionary<string, object>;
|
|
if (_selectedEmployee == null)
|
|
{
|
|
ClearBadgePreview();
|
|
return;
|
|
}
|
|
|
|
_currentBadgeType =
|
|
_selectedEmployee.GetValueOrDefault("BadgeType")?.ToString() ?? "Office";
|
|
BadgeTypePicker.SelectedItem = _currentBadgeType;
|
|
GuestImageSelector.IsVisible = _currentBadgeType == "Guest";
|
|
|
|
RenderBadgePreview(_selectedEmployee);
|
|
}
|
|
|
|
private void OnBadgeTypeChanged(object sender, EventArgs e)
|
|
{
|
|
if (_selectedEmployee == null)
|
|
return;
|
|
|
|
_currentBadgeType = BadgeTypePicker.SelectedItem?.ToString() ?? "Office";
|
|
GuestImageSelector.IsVisible = _currentBadgeType == "Guest";
|
|
|
|
string sql = "UPDATE dbo.tblData SET BadgeType = @type WHERE Data1 = @id";
|
|
_db.Execute(
|
|
sql,
|
|
new[]
|
|
{
|
|
new SqlParameter("@type", _currentBadgeType),
|
|
new SqlParameter("@id", _selectedEmployee["Data1"]),
|
|
}
|
|
);
|
|
|
|
_selectedEmployee["BadgeType"] = _currentBadgeType;
|
|
RenderBadgePreview(_selectedEmployee);
|
|
}
|
|
|
|
private void OnGuestImageChanged(object sender, EventArgs e)
|
|
{
|
|
_currentGuestImage = GuestImagePicker.SelectedItem?.ToString() ?? "Guest1.png";
|
|
if (_selectedEmployee != null && _currentBadgeType == "Guest")
|
|
RenderBadgePreview(_selectedEmployee);
|
|
}
|
|
|
|
private void ClearBadgePreview()
|
|
{
|
|
PreviewFrame.Content = null;
|
|
}
|
|
|
|
private void RenderBadgePreview(Dictionary<string, object> emp)
|
|
{
|
|
string firstName = (emp.GetValueOrDefault("Data8")?.ToString() ?? "").Trim();
|
|
string lastName = (emp.GetValueOrDefault("Data7")?.ToString() ?? "").Trim();
|
|
string recordNum = (emp.GetValueOrDefault("Data1")?.ToString() ?? "").Trim();
|
|
string department = (emp.GetValueOrDefault("Data9")?.ToString() ?? "").Trim();
|
|
string title = (emp.GetValueOrDefault("Data10")?.ToString() ?? "").Trim();
|
|
string data5 = (emp.GetValueOrDefault("Data5")?.ToString() ?? "").Trim();
|
|
|
|
string fullName = $"{firstName} {lastName}".Trim();
|
|
string barcode = $"*{recordNum}*";
|
|
|
|
string picCode = emp.GetValueOrDefault("picCode")?.ToString() ?? "";
|
|
string photoPath = string.IsNullOrEmpty(picCode)
|
|
? ""
|
|
: System.IO.Path.Combine(GetPhotoDir(), $"{picCode}.jpg"); // Fully qualified
|
|
|
|
double scale = SafeToDouble(emp.GetValueOrDefault("cropScale"), 1.0);
|
|
double tx = SafeToDouble(emp.GetValueOrDefault("cropX"), 0.0);
|
|
double ty = SafeToDouble(emp.GetValueOrDefault("cropY"), 0.0);
|
|
|
|
bool medicalBlue = false;
|
|
bool medicalRed = false;
|
|
|
|
var mainLayout = new HorizontalStackLayout
|
|
{
|
|
Spacing = 60,
|
|
Padding = 20,
|
|
HorizontalOptions = LayoutOptions.Center,
|
|
};
|
|
|
|
// FRONT BADGE
|
|
var frontLayout = new VerticalStackLayout { Spacing = 15 };
|
|
|
|
Color frontBg = Colors.White;
|
|
Color frontBorderColor = Colors.Gray;
|
|
|
|
switch (_currentBadgeType)
|
|
{
|
|
case "Plant":
|
|
frontBg = Color.FromArgb("#e8f5e8");
|
|
frontBorderColor = Colors.Green;
|
|
break;
|
|
case "Maintenance":
|
|
frontBg = Color.FromArgb("#fff3e0");
|
|
frontBorderColor = Colors.Orange;
|
|
break;
|
|
case "Guest":
|
|
frontBg = Color.FromArgb("#f3e8ff");
|
|
frontBorderColor = Colors.Purple;
|
|
break;
|
|
case "Visitor":
|
|
case "Vendor":
|
|
frontBg = Color.FromArgb("#ffebee");
|
|
frontBorderColor = Colors.Red;
|
|
break;
|
|
}
|
|
|
|
var frontBorder = new Border
|
|
{
|
|
Stroke = frontBorderColor,
|
|
StrokeThickness = 4,
|
|
BackgroundColor = frontBg,
|
|
Padding = 25,
|
|
WidthRequest = 380,
|
|
StrokeShape = new RoundRectangle { CornerRadius = 20 },
|
|
Shadow = new Shadow
|
|
{
|
|
Brush = SolidColorBrush.Black,
|
|
Offset = new Point(0, 4),
|
|
Radius = 10f,
|
|
Opacity = 0.3f,
|
|
},
|
|
Content = frontLayout,
|
|
};
|
|
|
|
frontLayout.Children.Add(
|
|
new Image
|
|
{
|
|
Source = PreviewLogoFront.Source,
|
|
HeightRequest = 70,
|
|
HorizontalOptions = LayoutOptions.Center,
|
|
Aspect = Aspect.AspectFit,
|
|
}
|
|
);
|
|
|
|
if (_currentBadgeType == "Guest")
|
|
{
|
|
frontLayout.Children.Add(
|
|
new Image
|
|
{
|
|
Source = ImageSource.FromResource(
|
|
$"FrymasterBadgeApp.Resources.Images.{_currentGuestImage}"
|
|
),
|
|
HeightRequest = 200,
|
|
WidthRequest = 200,
|
|
Aspect = Aspect.AspectFit,
|
|
}
|
|
);
|
|
}
|
|
else if (File.Exists(photoPath))
|
|
{
|
|
var photoImg = new Image
|
|
{
|
|
Source = ImageSource.FromFile(photoPath),
|
|
HeightRequest = 200,
|
|
WidthRequest = 200,
|
|
Aspect = Aspect.AspectFill,
|
|
Scale = scale,
|
|
TranslationX = tx,
|
|
TranslationY = ty,
|
|
};
|
|
frontLayout.Children.Add(photoImg);
|
|
}
|
|
else
|
|
{
|
|
frontLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = "No Photo",
|
|
FontSize = 18,
|
|
TextColor = Colors.Gray,
|
|
HorizontalTextAlignment = TextAlignment.Center,
|
|
}
|
|
);
|
|
}
|
|
|
|
frontLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = fullName,
|
|
FontSize = 24,
|
|
FontAttributes = FontAttributes.Bold,
|
|
HorizontalTextAlignment = TextAlignment.Center,
|
|
TextColor = Colors.Black,
|
|
}
|
|
);
|
|
|
|
if (!string.IsNullOrEmpty(title))
|
|
frontLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = title,
|
|
FontSize = 18,
|
|
HorizontalTextAlignment = TextAlignment.Center,
|
|
TextColor = Colors.Black,
|
|
}
|
|
);
|
|
|
|
if (!string.IsNullOrEmpty(department))
|
|
frontLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = department,
|
|
FontSize = 16,
|
|
HorizontalTextAlignment = TextAlignment.Center,
|
|
TextColor = Colors.Gray,
|
|
}
|
|
);
|
|
|
|
mainLayout.Children.Add(frontBorder);
|
|
|
|
// BACK BADGE
|
|
var backLayout = new VerticalStackLayout { Spacing = 12 };
|
|
|
|
var backBorder = new Border
|
|
{
|
|
Stroke = Colors.Gray,
|
|
StrokeThickness = 4,
|
|
BackgroundColor = Colors.White,
|
|
Padding = 25,
|
|
WidthRequest = 380,
|
|
StrokeShape = new RoundRectangle { CornerRadius = 20 },
|
|
Shadow = new Shadow
|
|
{
|
|
Brush = SolidColorBrush.Black,
|
|
Offset = new Point(0, 4),
|
|
Radius = 10f,
|
|
Opacity = 0.3f,
|
|
},
|
|
Content = backLayout,
|
|
};
|
|
|
|
backLayout.Children.Add(
|
|
new Image
|
|
{
|
|
Source = PreviewLogoFront.Source,
|
|
HeightRequest = 50,
|
|
HorizontalOptions = LayoutOptions.Center,
|
|
Aspect = Aspect.AspectFit,
|
|
}
|
|
);
|
|
|
|
backLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text =
|
|
$"This badge is the property of {_currentCompany.GetValueOrDefault("Name")} L.L.C.",
|
|
FontSize = 14,
|
|
FontAttributes = FontAttributes.Bold,
|
|
HorizontalTextAlignment = TextAlignment.Center,
|
|
TextColor = Colors.Black,
|
|
}
|
|
);
|
|
|
|
backLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = $"ID: {recordNum}",
|
|
FontSize = 16,
|
|
TextColor = Colors.Black,
|
|
}
|
|
);
|
|
backLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = title,
|
|
FontSize = 16,
|
|
TextColor = Colors.Black,
|
|
}
|
|
);
|
|
backLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = data5,
|
|
FontSize = 16,
|
|
TextColor = Colors.Black,
|
|
}
|
|
);
|
|
|
|
string address = _currentCompany.GetValueOrDefault("Address")?.ToString() ?? "";
|
|
if (!string.IsNullOrEmpty(address))
|
|
backLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = address,
|
|
FontSize = 14,
|
|
TextColor = Colors.Black,
|
|
}
|
|
);
|
|
|
|
var locationParts = new[]
|
|
{
|
|
_currentCompany.GetValueOrDefault("City")?.ToString(),
|
|
_currentCompany.GetValueOrDefault("State")?.ToString(),
|
|
_currentCompany.GetValueOrDefault("Zip")?.ToString(),
|
|
}
|
|
.Where(p => !string.IsNullOrEmpty(p))
|
|
.ToArray();
|
|
|
|
if (locationParts.Length > 0)
|
|
backLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = string.Join(", ", locationParts),
|
|
FontSize = 14,
|
|
TextColor = Colors.Black,
|
|
}
|
|
);
|
|
|
|
string phone = _currentCompany.GetValueOrDefault("Phone")?.ToString() ?? "";
|
|
if (!string.IsNullOrEmpty(phone))
|
|
backLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = phone,
|
|
FontSize = 14,
|
|
TextColor = Colors.Black,
|
|
}
|
|
);
|
|
|
|
if (medicalBlue || medicalRed)
|
|
{
|
|
var medStack = new HorizontalStackLayout
|
|
{
|
|
HorizontalOptions = LayoutOptions.Center,
|
|
Spacing = 10,
|
|
};
|
|
if (medicalBlue)
|
|
medStack.Children.Add(
|
|
new Label
|
|
{
|
|
Text = "🩺",
|
|
FontSize = 36,
|
|
TextColor = Colors.Blue,
|
|
}
|
|
);
|
|
if (medicalRed)
|
|
medStack.Children.Add(
|
|
new Label
|
|
{
|
|
Text = "🩺",
|
|
FontSize = 36,
|
|
TextColor = Colors.Red,
|
|
}
|
|
);
|
|
backLayout.Children.Add(medStack);
|
|
}
|
|
|
|
if (_currentBadgeType == "Office" || _currentBadgeType == "Plant")
|
|
{
|
|
backLayout.Children.Add(
|
|
new Label
|
|
{
|
|
Text = barcode,
|
|
FontFamily = "BarcodeFont",
|
|
FontSize = 50,
|
|
HorizontalTextAlignment = TextAlignment.Center,
|
|
TextColor = Colors.Black,
|
|
}
|
|
);
|
|
}
|
|
|
|
mainLayout.Children.Add(backBorder);
|
|
|
|
PreviewFrame.Content = mainLayout;
|
|
}
|
|
|
|
private async void OnTakePhotoClicked(object sender, EventArgs e)
|
|
{
|
|
if (_selectedEmployee == null)
|
|
return;
|
|
|
|
try
|
|
{
|
|
var photo = await MediaPicker.Default.CapturePhotoAsync();
|
|
if (photo != null)
|
|
{
|
|
_tempCapturePath = System.IO.Path.Combine(
|
|
FileSystem.CacheDirectory,
|
|
"temp_editor.jpg"
|
|
); // Fully qualified
|
|
using var source = await photo.OpenReadAsync();
|
|
using var dest = File.OpenWrite(_tempCapturePath);
|
|
await source.CopyToAsync(dest);
|
|
|
|
EditorPhotoPreview.Source = ImageSource.FromFile(_tempCapturePath);
|
|
_editX = _editY = 0;
|
|
EditorPhotoPreview.TranslationX = EditorPhotoPreview.TranslationY = 0;
|
|
ZoomSlider.Value = 1;
|
|
PhotoEditorOverlay.IsVisible = true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await DisplayAlert("Camera Error", ex.Message, "OK");
|
|
}
|
|
}
|
|
|
|
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
|
|
{
|
|
if (e.StatusType == GestureStatus.Running)
|
|
{
|
|
EditorPhotoPreview.TranslationX = _editX + e.TotalX;
|
|
EditorPhotoPreview.TranslationY = _editY + e.TotalY;
|
|
}
|
|
else if (e.StatusType == GestureStatus.Completed)
|
|
{
|
|
_editX = EditorPhotoPreview.TranslationX;
|
|
_editY = EditorPhotoPreview.TranslationY;
|
|
}
|
|
}
|
|
|
|
private async void OnApplyPhoto(object sender, EventArgs e)
|
|
{
|
|
if (_selectedEmployee == null)
|
|
return;
|
|
|
|
try
|
|
{
|
|
string firstName = (
|
|
_selectedEmployee.GetValueOrDefault("Data8")?.ToString() ?? ""
|
|
).Trim();
|
|
string lastName = (
|
|
_selectedEmployee.GetValueOrDefault("Data7")?.ToString() ?? ""
|
|
).Trim();
|
|
string recordNum = (
|
|
_selectedEmployee.GetValueOrDefault("Data1")?.ToString() ?? ""
|
|
).Trim();
|
|
|
|
string picCode = $"{lastName}{recordNum}{firstName}{lastName}";
|
|
string finalPath = System.IO.Path.Combine(GetPhotoDir(), $"{picCode}.jpg"); // Fully qualified
|
|
|
|
File.Copy(_tempCapturePath, finalPath, true);
|
|
|
|
string sql =
|
|
@"UPDATE dbo.tblData SET picCode = @pic, cropScale = @s, cropX = @x, cropY = @y WHERE Data1 = @id";
|
|
|
|
_db.Execute(
|
|
sql,
|
|
new[]
|
|
{
|
|
new SqlParameter("@pic", picCode),
|
|
new SqlParameter("@s", ZoomSlider.Value),
|
|
new SqlParameter("@x", EditorPhotoPreview.TranslationX),
|
|
new SqlParameter("@y", EditorPhotoPreview.TranslationY),
|
|
new SqlParameter("@id", recordNum),
|
|
}
|
|
);
|
|
|
|
_selectedEmployee["picCode"] = picCode;
|
|
_selectedEmployee["cropScale"] = ZoomSlider.Value;
|
|
_selectedEmployee["cropX"] = EditorPhotoPreview.TranslationX;
|
|
_selectedEmployee["cropY"] = EditorPhotoPreview.TranslationY;
|
|
|
|
RenderBadgePreview(_selectedEmployee);
|
|
PhotoEditorOverlay.IsVisible = false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await DisplayAlert("Save Error", ex.Message, "OK");
|
|
}
|
|
}
|
|
|
|
private void OnCancelPhoto(object sender, EventArgs e) => PhotoEditorOverlay.IsVisible = false;
|
|
|
|
private double SafeToDouble(object? value, double defaultValue)
|
|
{
|
|
if (value == null || value == DBNull.Value)
|
|
return defaultValue;
|
|
return double.TryParse(value.ToString(), out double d) ? d : defaultValue;
|
|
}
|
|
|
|
private void OnPrintClicked(object sender, EventArgs e)
|
|
{
|
|
if (_selectedEmployee != null)
|
|
_printerService.PrintBadge(_selectedEmployee, _currentCompany, _currentBadgeType);
|
|
}
|
|
}
|