Skip to content

Commit

Permalink
Merge pull request #34 from rgomezr/release-0.3.0
Browse files Browse the repository at this point in the history
`Release-0.3.0` into `main`
  • Loading branch information
rgomezr authored Aug 20, 2023
2 parents b550a1c + 27a125b commit 660d730
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 61 deletions.
14 changes: 14 additions & 0 deletions ClockingApp/Controllers/ClockingController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ public async Task<ActionResult> FinishBreak([FromBody] string clockingId)
}
}

[HttpDelete]
public async Task<ActionResult> Clocking([FromBody] string clockingId)
{
bool isDeleted = await _clockingService._clockingRepo.DeleteByIdAsync(clockingId);
return Json(isDeleted);
}


public async Task<ActionResult> GetAllClockingsForUserAndWeek(DateTime weekDate)
{
int weekNumber = ISOWeek.GetWeekOfYear(weekDate);
Expand Down Expand Up @@ -145,9 +153,15 @@ public async Task<ActionResult> GetClockingInvoiceForWeek(int weekNumber, int we
clocking.SetTimeZoneForClockingWorkAndBreaks(specifiedTimeZone);
}
WeeklyClockingInfo weeklyClockingInfo = new WeeklyClockingInfo(weekClockings);
weeklyClockingInfo.IsInvoiceView = true;
return View("ClockingsInvoicePDF", weeklyClockingInfo);
}

public async Task<ActionResult> EditClocking(string clockingId)
{
return View("EditClocking", model:clockingId);
}

private async Task<Clocking> RetrieveClockingById(string clockingId)
{
return await _clockingService._clockingRepo.FindByIdAsync(clockingId);
Expand Down
3 changes: 2 additions & 1 deletion ClockingApp/Models/ClockingData/WeeklyClockingInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ public class WeeklyClockingInfo
{
public IList<Clocking>? WeeklyClockings { get; set; }
public double OvertimeHours { get; set; }
public bool HasOvertime => (OvertimeHours > 0);
public bool IsInvoiceView { get; set; } = false;
public bool HasOvertime => (OvertimeHours > 0);
public string OvertimeHours_formatted => String.Format("{0}{1}", this.OvertimeHours.ToString("##.##"), "h");
public bool HasClockings => (WeeklyClockings != null && WeeklyClockings.Any());
public int ClockingWeek => HasClockings
Expand Down
2 changes: 1 addition & 1 deletion ClockingApp/Repository/IMongoRepositoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface IMongoRepositoryBase<TDocument> where TDocument : IDocument
Task<IEnumerable<TDocument>> FindAllAsync(Expression<Func<TDocument, bool>> filter);
Task FindOneAndReplaceAsync(Expression<Func<TDocument, bool>> filter, TDocument document);
Task InsertOneAsync(TDocument document);
Task DeleteByIdAsync(string id);
Task<bool> DeleteByIdAsync(string id);
}
}

85 changes: 43 additions & 42 deletions ClockingApp/Repository/MongoRepositoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,52 +7,53 @@

namespace ClockingApp.Repository
{
public class MongoRepositoryBase<TDocument> : IMongoRepositoryBase<TDocument> where TDocument : IDocument
{
private readonly IMongoCollection<TDocument> _collection;

public MongoRepositoryBase(IMongoClient mongoClient, IMongoDBSettings mongoSettings)
{
_collection = mongoClient.GetDatabase(mongoSettings.DatabaseName).GetCollection<TDocument>(GetCollectionName(typeof(TDocument)));
}

private protected string GetCollectionName (Type documentType)
{
var attribute = documentType.
GetCustomAttributes(typeof(BsonCollectionAttribute), true).FirstOrDefault();
return attribute != null ? ((BsonCollectionAttribute)attribute).CollectionName : "";
}

public virtual async Task<TDocument> FindOneAsync (Expression<Func<TDocument, bool>> filter)
{
return (await _collection.FindAsync(filter)).FirstOrDefault();
}

public virtual async Task InsertOneAsync (TDocument document)
{
await _collection.InsertOneAsync(document);
}

public virtual async Task FindOneAndReplaceAsync (Expression<Func<TDocument, bool>> filter, TDocument document)
{
await _collection.FindOneAndReplaceAsync(filter, document);
}
public class MongoRepositoryBase<TDocument> : IMongoRepositoryBase<TDocument> where TDocument : IDocument
{
private readonly IMongoCollection<TDocument> _collection;

public MongoRepositoryBase(IMongoClient mongoClient, IMongoDBSettings mongoSettings)
{
_collection = mongoClient.GetDatabase(mongoSettings.DatabaseName).GetCollection<TDocument>(GetCollectionName(typeof(TDocument)));
}

private protected string GetCollectionName(Type documentType)
{
var attribute = documentType.
GetCustomAttributes(typeof(BsonCollectionAttribute), true).FirstOrDefault();
return attribute != null ? ((BsonCollectionAttribute)attribute).CollectionName : "";
}

public virtual async Task<TDocument> FindOneAsync(Expression<Func<TDocument, bool>> filter)
{
return (await _collection.FindAsync(filter)).FirstOrDefault();
}

public virtual async Task InsertOneAsync(TDocument document)
{
await _collection.InsertOneAsync(document);
}

public virtual async Task FindOneAndReplaceAsync(Expression<Func<TDocument, bool>> filter, TDocument document)
{
await _collection.FindOneAndReplaceAsync(filter, document);
}

public virtual async Task<IEnumerable<TDocument>> FindAllAsync(Expression<Func<TDocument, bool>> filter)
{
return (await _collection.FindAsync(filter)).ToEnumerable();
}
public virtual async Task<TDocument> FindByIdAsync(string id)
{
ObjectId objectId = new (id);
FilterDefinition<TDocument> filter = Builders<TDocument>.Filter.Eq(doc => doc._id, objectId);
return (await _collection.FindAsync(filter)).SingleOrDefault();
}
public virtual async Task DeleteByIdAsync(string id)
{
{
return (await _collection.FindAsync(filter)).ToEnumerable();
}
public virtual async Task<TDocument> FindByIdAsync(string id)
{
ObjectId objectId = new(id);
FilterDefinition<TDocument> filter = Builders<TDocument>.Filter.Eq(doc => doc._id, objectId);
return (await _collection.FindAsync(filter)).SingleOrDefault();
}
public virtual async Task<bool> DeleteByIdAsync(string id)
{
ObjectId objectId = new(id);
FilterDefinition<TDocument> filter = Builders<TDocument>.Filter.Eq(doc => doc._id, objectId);
await _collection.FindOneAndDeleteAsync(filter);
TDocument deletedDoc = await _collection.FindOneAndDeleteAsync(filter);
return deletedDoc != null;
}

}
Expand Down
2 changes: 2 additions & 0 deletions ClockingApp/Views/Clocking/EditClocking.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@model string
<p>@Model</p>
39 changes: 29 additions & 10 deletions ClockingApp/Views/Shared/Components/WeeklyClocking/Default.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
</div>
</div>
<p class="groupLabel smallMarginTop">Breakdown</p>
<table class="table table-borderless">
<table class="table table-borderless clockingTable" id="clockingTable">
<thead>
<tr>
<th>Date</th>
Expand All @@ -41,28 +41,47 @@
<th>Work Duration</th>
<th>Breaks</th>
<th>Breaks Breakdown</th>
@if (!Model.IsInvoiceView)
{
<th></th>
}
</tr>
</thead>
<tbody>
@foreach (ClockingApp.Models.ClockingData.Clocking clocking in Model.WeeklyClockings)
@foreach (var item in Model.WeeklyClockings.Select((clocking, index) => new { clocking, index }))
{
<tr>
<td>@clocking.ClockingDate.ToString("D")</td>
<td>@clocking.WorkDay.StartDate_formatted</td>
<td>@clocking.WorkDay.EndDate_formatted</td>
<td class="hasSecondSmallPrint">@clocking.WorkingHoursPaid_formatted</td>
<td>@String.Format("{0} Breaks ({1})", clocking.NumberOfBreaks, clocking.BreakDuration_formatted)</td>
<td>
@if (clocking.Breaks != null)
@item.clocking.ClockingDate.ToString("D")
</td>
<td>@item.clocking.WorkDay.StartDate_formatted</td>
<td>@item.clocking.WorkDay.EndDate_formatted</td>
<td class="hasSecondSmallPrint">@item.clocking.WorkingHoursPaid_formatted</td>
<td>@String.Format("{0} Breaks ({1})", item.clocking.NumberOfBreaks, item.clocking.BreakDuration_formatted)</td>
<td>
@if (item.clocking.Breaks != null)
{
<ul>
@foreach (var _break in clocking.Breaks)
@foreach (var _break in item.clocking.Breaks)
{
<li>@String.Format("{0} → {1} ({2})", _break.StartDate_formatted, _break.EndDate_formatted, _break.Duration_formatted)</li>
<li>
@String.Format("{0} → {1} ({2})", _break.StartDate_formatted
, _break.EndDate_formatted, _break.Duration_formatted)
</li>
}
</ul>
}
</td>
@if (!Model.IsInvoiceView)
{
<td>
<div class="optionsMenu">
<div class="containerGroup initial">
<button type="button" class="inlineEditButton btn btn-light" title="Delete this Clocking" onclick="DeleteClocking('@(item.clocking._id)', '@(item.clocking.ClockingDate.ToString("D"))', 'clockingTable', '@(item.index)')">×</button>
</div>
</div>
</td>
}
</tr>
}
</tbody>
Expand Down
1 change: 1 addition & 0 deletions ClockingApp/Views/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/Clocking.js" asp-append-version="true"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert2.all.min.js"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
Expand Down
2 changes: 1 addition & 1 deletion ClockingApp/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"ClockingSettings": {
"PaidBreakTime": "15",
"OvertimeThresholdHours": "0,25",
"OvertimeThresholdHours": "0.25",
"WeeklyDefaultHours": {
"Monday": {
"WeekDay": "Monday",
Expand Down
23 changes: 17 additions & 6 deletions ClockingApp/wwwroot/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,6 @@ body {
table th {
text-align: left;
}
/* table th:hover {
border: 0.5px solid;
border-radius: 15px;
border-color: rgba(0,0,0,0.04);
background-color: rgba(0,0,0,0.04);
}*/

.hasSmallPrint {
}
Expand Down Expand Up @@ -153,3 +147,20 @@ table th {
font-size: medium;
color: rgba(70,130,180, 30);
}

.inlineEditButton {
font-size: large;
padding: 2px 5px;

}

.optionsMenu {
visibility: hidden;
opacity: 0;
transition: visibility 0.2s linear, opacity 0.2s linear;
}

.clockingTable tbody tr:hover .optionsMenu {
visibility: visible;
opacity: 1;
}
60 changes: 60 additions & 0 deletions ClockingApp/wwwroot/js/Clocking.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,64 @@ function FinishBreak(clockingId) {
window.location.href = _dataBack;
}
});
}

function DeleteTableRowByTableIndex(tableId, tableRowIndex) {
/* tableRowIndex starts in zero within tbody and table.deleteRow()
* considers 0 as the table head - Therefore, we increment index always in 1.
* parseInt is used to make sure that it does not join two strings with the sum
* operation.
*/
var dataTableRowIndex = parseInt(tableRowIndex) + 1;
var table = document.getElementById(tableId);
if (table) {
table.deleteRow(dataTableRowIndex);
}
}

function DeleteClockingRequest(clockingId) {
return new Promise(resolve => {
$.ajax({
type: "DELETE",
url: "Clocking/Clocking",
dataType: "json",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(clockingId),
success: function (response) {
if (response === true) {
resolve(true);
} else {
resolve(false);
}
}
});
});

}

async function DeleteClocking(clockingId, clockingDate, tableId, tableRowIndexToDelete) {
let userRequestResponse = await Swal.fire({
icon: 'question',
title: 'Removing Clocking',
text: `This will remove Clocking for ${clockingDate}`,
showConfirmButton: true,
showCancelButton: true,
confirmButtonText: 'Delete it!'
}).then((result) => {
return result.isConfirmed;
});
if (userRequestResponse === true) {
const deleteResponse = await DeleteClockingRequest(clockingId);
if (deleteResponse === true) {
DeleteTableRowByTableIndex(tableId, tableRowIndexToDelete);
Swal.fire('Deleted!'
, 'Clocking was deleted'
, 'success');
} else {
Swal.fire('Error!'
, 'Something went wrong'
, 'error');
}
}

}

0 comments on commit 660d730

Please sign in to comment.