M Talha Mohsin
M Talha Mohsin
02-131222-109
File Structure:
// Controllers/HomeController.cs
using Microsoft.AspNetCore.Mvc;
namespace InnovaytePayroll.Controllers;
// Controllers/PayrollController.cs
using InnovaytePayroll.Models.Employees;
using InnovaytePayroll.Services;
using Microsoft.AspNetCore.Mvc;
namespace InnovaytePayroll.Controllers;
// Models/Employees/ContractEmployee.cs
namespace InnovaytePayroll.Models.Employees;
// Models/Employees/EmployeeBase.cs
namespace InnovaytePayroll.Models.Employees;
// Models/Employees/FreelanceWorker.cs
namespace InnovaytePayroll.Models.Employees;
// Models/Employees/FullTimeEmployee.cs
namespace InnovaytePayroll.Models.Employees;
// Models/Employees/PartTimeEmployee.cs
namespace InnovaytePayroll.Models.Employees;
// Models/PayrollCalculationService.cs
using InnovaytePayroll.Models.Employees;
namespace InnovaytePayroll.Models;
PartTimeEmployee pt => (
pt.CalculateSalary(),
pt.IsOvertime()
? $"Part-time earnings with overtime warning! ({pt.HoursWorkedPerWeek}
hours/week)"
: $"Part-time earnings for {pt.HoursWorkedPerWeek} hours/week"
),
ContractEmployee ce => (
ce.CalculateEarnings(),
ce.Type == ContractEmployee.ContractType.FixedFee
? $"Fixed fee contract payment"
: $"Milestone payment ({ce.MilestonesCompleted} of {ce.TotalMilestones}
completed)"
),
FreelanceWorker fw => (
fw.CalculateEarnings(),
$"Freelance payment for {fw.Tasks.Sum(t => t.Count)} tasks " +
$"across {fw.Tasks.Select(t => t.Category).Distinct().Count()} categories"
),
// Services/IPayrollCalculator.cs
using InnovaytePayroll.Models.Employees;
namespace InnovaytePayroll.Services;
namespace InnovaytePayroll.Services;
PartTimeEmployee pt =>
$"Part-time employee: Monthly earnings ${pt.CalculateSalary():0.00} " +
$"at ${pt.HourlyRate:0.00}/hour for {pt.HoursWorkedPerWeek} hours/week. " +
(pt.IsOvertime() ? "Warning: Overtime hours detected!" : ""),
ContractEmployee ce =>
$"Contract employee: {ce.Type} model. " +
$"Earned ${ce.CalculateEarnings():0.00} of ${ce.ProjectFee:0.00} " +
(ce.Type == ContractEmployee.ContractType.MilestoneBased
? $"(Completed {ce.MilestonesCompleted} of {ce.TotalMilestones} milestones)"
: ""),
FreelanceWorker fw =>
$"Freelancer: Earned ${fw.CalculateEarnings():0.00} for {fw.Tasks.Sum(t => t.Count)}
tasks " +
$"across {fw.Tasks.Select(t => t.Category).Distinct().Count()} categories",
@* Views/Payroll/_ContractForm.cshtml *@
@model ContractEmployee
<div class="mb-3">
<label asp-for="Name" class="form-label">Contractor Name</label>
<input asp-for="Name" class="form-control" required />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="mb-3">
<label class="form-label">Contract Type</label>
<div class="form-check">
<input class="form-check-input" type="radio" asp-for="Type"
value="@ContractEmployee.ContractType.FixedFee" checked />
<label class="form-check-label">Fixed Fee</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" asp-for="Type"
value="@ContractEmployee.ContractType.MilestoneBased" />
<label class="form-check-label">Milestone Based</label>
</div>
</div>
<div class="mb-3">
<label asp-for="ProjectFee" class="form-label">Project Fee ($)</label>
<input asp-for="ProjectFee" class="form-control" required min="0" step="0.01" />
<span asp-validation-for="ProjectFee" class="text-danger"></span>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg">Calculate Earnings</button>
</div>
</form>
@* Views/Payroll/_FreelanceForm.cshtml *@
@model FreelanceWorker
<div class="mb-3">
<label asp-for="Name" class="form-label">Freelancer Name</label>
<input asp-for="Name" class="form-control" required />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="mb-3">
<h5>Tasks Completed</h5>
<div id="tasksContainer">
@if (Model.Tasks != null && Model.Tasks.Any())
{
for (int i = 0; i < Model.Tasks.Count; i++)
{
<div class="task-row mb-3">
<div class="row">
<div class="col-md-5">
<input asp-for="Tasks[i].Category" class="form-control"
placeholder="Task category" required />
</div>
<div class="col-md-3">
<input asp-for="Tasks[i].Rate" class="form-control" placeholder="Rate"
min="0" step="0.01" required />
</div>
<div class="col-md-3">
<input asp-for="Tasks[i].Count" class="form-control" placeholder="Count"
min="1" required />
</div>
<div class="col-md-1">
<button type="button" class="btn btn-danger remove-task">×</button>
</div>
</div>
</div>
}
}
else
{
<div class="task-row mb-3">
<div class="row">
<div class="col-md-5">
<input name="Tasks[0].Category" class="form-control" placeholder="Task
category" required />
</div>
<div class="col-md-3">
<input name="Tasks[0].Rate" class="form-control" placeholder="Rate"
min="0" step="0.01" required />
</div>
<div class="col-md-3">
<input name="Tasks[0].Count" class="form-control" placeholder="Count"
min="1" required />
</div>
<div class="col-md-1">
<button type="button" class="btn btn-danger remove-task">×</button>
</div>
</div>
</div>
}
</div>
<button type="button" id="addTaskBtn" class="btn btn-secondary btn-sm">
<i class="fas fa-plus"></i> Add Task
</button>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg">Calculate Earnings</button>
</div>
</form>
@* Views/Payroll/_FullTimeForm.cshtml *@
@model FullTimeEmployee
<div class="mb-3">
<label asp-for="Name" class="form-label">Employee Name</label>
<input asp-for="Name" class="form-control" required />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label asp-for="AnnualSalary" class="form-label">Annual Salary ($)</label>
<input asp-for="AnnualSalary" class="form-control" required min="0" />
<span asp-validation-for="AnnualSalary" class="text-danger"></span>
</div>
<div class="col-md-6 mb-3">
<label asp-for="WorkingHoursPerWeek" class="form-label">Working
Hours/Week</label>
<input asp-for="WorkingHoursPerWeek" class="form-control" required min="1"
max="80" />
<span asp-validation-for="WorkingHoursPerWeek" class="text-danger"></span>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label asp-for="WeeksPerYear" class="form-label">Weeks/Year</label>
<input asp-for="WeeksPerYear" class="form-control" required min="1" max="52" />
<span asp-validation-for="WeeksPerYear" class="text-danger"></span>
</div>
<div class="col-md-6 mb-3">
<label asp-for="LoggedHours" class="form-label">Logged Hours (Current
Month)</label>
<input asp-for="LoggedHours" class="form-control" required min="0" />
<span asp-validation-for="LoggedHours" class="text-danger"></span>
</div>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg">Calculate Salary</button>
</div>
</form>
@* Views/Payroll/_PartTimeForm.cshtml *@
@model PartTimeEmployee
<form asp-action="Calculate" asp-controller="Payroll" method="post">
<input type="hidden" name="EmployeeType" value="PartTime" />
<div class="mb-3">
<label asp-for="Name" class="form-label">Employee Name</label>
<input asp-for="Name" class="form-control" required />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label asp-for="HourlyRate" class="form-label">Hourly Rate ($)</label>
<input asp-for="HourlyRate" class="form-control" required min="0" step="0.01" />
<span asp-validation-for="HourlyRate" class="text-danger"></span>
</div>
<div class="col-md-6 mb-3">
<label asp-for="HoursWorkedPerWeek" class="form-label">Hours
Worked/Week</label>
<input asp-for="HoursWorkedPerWeek" class="form-control" required min="0"
max="60" />
<span asp-validation-for="HoursWorkedPerWeek" class="text-danger"></span>
<small class="text-muted">Max allowed: @PartTimeEmployee.MaxHoursPerWeek
hours/week</small>
</div>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg">Calculate Salary</button>
</div>
</form>
@* Views/Payroll/Index.cshtml *@
@model InnovaytePayroll.Models.Employees.EmployeeBase
@{
ViewData["Title"] = "Payroll Calculator";
}
@section Scripts {
<script src="~/js/payroll.js"></script>
}
@* Views/Payroll/Results.cshtml *@
@model PayrollResult
@{
ViewData["Title"] = "Payroll Results";
}
<div class="details-section">
<h5 class="mb-3">Details</h5>
@if (Model.Employee is FullTimeEmployee ft)
{
<dl class="row">
<dt class="col-sm-4">Annual Salary</dt>
<dd class="col-sm-8">@ft.AnnualSalary.ToString("C")</dd>
<dt class="col-sm-4">Weeks/Year</dt>
<dd class="col-sm-8">@ft.WeeksPerYear</dd>
@if (pt.IsOvertime())
{
<dt class="col-sm-4">Warning</dt>
<dd class="col-sm-8">
<div class="alert alert-warning">
Overtime detected! Max allowed is
@PartTimeEmployee.MaxHoursPerWeek hours/week.
</div>
</dd>
}
</dl>
}
else if (Model.Employee is ContractEmployee ce)
{
<dl class="row">
<dt class="col-sm-4">Contract Type</dt>
<dd class="col-sm-8">@ce.Type</dd>
/* wwwroot/css/purple-theme.css */
:root {
--primary-color: #6a0dad;
--primary-light: #9c27b0;
--primary-dark: #4a148c;
--secondary-color: #e1bee7;
--accent-color: #ff4081;
--text-on-primary: #ffffff;
--text-on-secondary: #000000;
--background: #f3e5f5;
--card-bg: #ffffff;
--input-bg: #f5f5f5;
}
body {
background-color: var(--background);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.navbar {
background-color: var(--primary-color) !important;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
.navbar-brand, .nav-link {
color: var(--text-on-primary) !important;
}
.btn-primary {
background-color: var(--primary-color);
border-color: var(--primary-dark);
}
.btn-primary:hover {
background-color: var(--primary-light);
border-color: var(--primary-color);
}
.card {
border: none;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
background-color: var(--card-bg);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 6px 25px rgba(0, 0, 0, 0.15);
}
.form-control:focus {
border-color: var(--primary-light);
box-shadow: 0 0 0 0.25rem rgba(154, 39, 176, 0.25);
}
.employee-type-tabs .nav-link {
color: var(--primary-dark);
border: none;
padding: 12px 20px;
font-weight: 500;
}
.employee-type-tabs .nav-link.active {
color: var(--accent-color);
background-color: transparent;
border-bottom: 3px solid var(--accent-color);
}
.result-display {
background: linear-gradient(135deg, var(--primary-light), var(--primary-dark));
color: white;
border-radius: 10px;
padding: 20px;
animation: fadeIn 0.5s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.alert-warning {
background-color: #fff3cd;
border-color: #ffeeba;
color: #856404;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(255, 193, 7, 0.7);
}
70% {
box-shadow: 0 0 0 10px rgba(255, 193, 7, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(255, 193, 7, 0);
}
}
/* wwwroot/css/site.css */
/* Base styles that work with the purple theme */
html {
font-size: 14px;
}
html {
position: relative;
min-height: 100%;
}
body {
margin-bottom: 60px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.text-purple {
color: #6a0dad;
}
.bg-purple {
background-color: #6a0dad;
}
.loading-spinner {
display: inline-block;
width: 2rem;
height: 2rem;
vertical-align: text-bottom;
border: 0.25em solid currentColor;
border-right-color: transparent;
border-radius: 50%;
animation: spinner-border .75s linear infinite;
}
@keyframes spinner-border {
to {
transform: rotate(360deg);
}
}
.card, .card * {
visibility: visible;
}
.card {
position: absolute;
left: 0;
top: 0;
width: 100%;
border: none;
box-shadow: none;
}
.no-print {
display: none !important;
}
}
// wwwroot/js/payroll.js
document.addEventListener('DOMContentLoaded', function () {
// Initialize tooltips
$('[data-toggle="tooltip"]').tooltip();
// Program.cs
using InnovaytePayroll.Services;
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Github Repositry:
Link:
https://github.com/avbcc/InnovaytePayroll.git
Output: