Skip to content

Commit f22fa5b

Browse files
authored
Merge pull request #7 from SensitTechnologies/production-log-modularity
Production Log Overhaul
2 parents 31577c6 + fed84cb commit f22fa5b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2070
-343
lines changed

MESS/MESS.Blazor/Components/App.razor

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
<link rel="stylesheet" href="@Assets["MESS.Blazor.styles.css"]"/>
1111
<ImportMap/>
1212
<link rel="icon" type="image/png" href="favicon.png"/>
13-
<HeadOutlet/>
14-
</head>
13+
<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />
14+
</head>
1515

1616
<body>
17-
<Routes @rendermode="InteractiveServer"/>
17+
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />
1818
<script src="_framework/blazor.web.js"></script>
1919
</body>
2020

Lines changed: 73 additions & 249 deletions
Original file line numberDiff line numberDiff line change
@@ -1,269 +1,93 @@
11
@page "/production-log/new"
22
@page "/production-log/edit/{logId:int}"
33
@using MESS.Data.Models
4+
@using MESS.Services.BrowserCacheManager
5+
@using MESS.Services.Product
46
@using MESS.Services.ProductionLog
57
@using MESS.Services.WorkInstruction
6-
@using Serilog
8+
@using MESS.Blazor.Components.Utility
9+
@using MESS.Services.SessionManager
10+
@using MESS.Services.WorkStation
711
@inject IProductionLogService ProductionLogService
812
@inject NavigationManager NavigationManager
913
@inject IWorkInstructionService WorkInstructionService
10-
@rendermode InteractiveServer
11-
12-
<EditForm FormName="EditProductionLog" Model="@ProductionLog" OnValidSubmit="HandleSubmit">
13-
<DataAnnotationsValidator />
14-
<div class="mb-3">
15-
<label for="Name" class="form-label">Product Name</label>
16-
<div class="col-md-4">
17-
@if (ProductionLog.Product != null)
18-
{
19-
<InputText class="form-control" @bind-Value="ProductionLog.Product.Name"/>
20-
<ValidationMessage For="@(() => ProductionLog.Product.Name)" />
21-
}
22-
</div>
23-
24-
<div>
25-
@if (WorkInstructions != null)
26-
{
27-
<select @bind="SelectedWorkInstructionId">
28-
<option value="">Select Work Instruction</option>
29-
@foreach (var instruction in WorkInstructions)
14+
@inject IProductService ProductService
15+
@inject ILocalCacheManager LocalCacheManager
16+
@inject IWorkStationService WorkStationService
17+
@inject ISessionManager SessionManager
18+
19+
<PageTitle>@Title</PageTitle>
20+
<ErrorBoundary>
21+
<ChildContent>
22+
<EditForm class="container" FormName="EditProductionLog" Model="ProductionLog" OnValidSubmit="HandleSubmit">
23+
<DataAnnotationsValidator/>
24+
<ValidationSummary/>
25+
<TimeFormValidator TModel="ProductionLog" Validator="_validator"></TimeFormValidator>
26+
<div class="mb-3">
27+
<div class="container ps-0 d-inline-flex justify-content-between gap-4 mb-2 flex-wrap">
28+
@if (!IsWorkflowActive && !IsEditMode)
3029
{
31-
<option value="@instruction.Id">@instruction.Title</option>
30+
<WorkStationSelect WorkStations="@WorkStations" OnWorkStationSelected="@SetActiveWorkStation"/>
31+
var stationProducts = LoadAssociatedProductsFromStation();
32+
<ProductSelect Disabled="@(string.IsNullOrWhiteSpace(ActiveWorkStation))" Products="@stationProducts" OnProductSelected="@SetActiveProduct"/>
3233
}
33-
</select>
34-
35-
}
36-
</div>
37-
38-
<div>
39-
@if (ActiveWorkInstruction != null)
40-
{
41-
<ul class="list-group list-group-numbered container">
42-
@foreach (var step in ActiveWorkInstruction.Steps)
34+
else
4335
{
44-
var logStep = ProductionLog.LogSteps?.FirstOrDefault(ls => ls.WorkInstructionStepId == step.Id);
45-
var isChecked = logStep?.Success ?? false;
46-
47-
if (logStep == null && ProductionLog.LogSteps != null)
48-
{
49-
logStep = new ProductionLogStep { WorkInstructionStepId = step.Id, ProductionLogId = ProductionLog.Id };
50-
ProductionLog.LogSteps.Add(logStep);
51-
}
52-
53-
<li class="list-group-item btn-group mb-2" role="group">
54-
<div class="row">
55-
<div class="col-8">
56-
@step.Name
57-
</div>
58-
59-
<div class="col-4">
60-
<input type="radio"
61-
checked="@isChecked"
62-
autocomplete="off"
63-
@onclick="() => ShowOptionalNotesField = !ShowOptionalNotesField"
64-
class="btn-check"
65-
name="radioBtn{@step.Name}"
66-
id="radioFailureBtn{@step.Name}"
67-
@onchange="@(e => OnStepCompleted(step, e, false))"/>
68-
<label class="btn btn-outline-danger" for="radioFailureBtn{@step.Name}">Failure</label>
69-
70-
<input type="radio"
71-
checked="@isChecked"
72-
autocomplete="off"
73-
class="btn-check"
74-
name="radioBtn{@step.Name}"
75-
id="radioSuccessBtn{@step.Name}"
76-
@onchange="@(e => OnStepCompleted(step, e, true))"/>
77-
<label class="btn btn-outline-success" for="radioSuccessBtn{@step.Name}">Success</label>
78-
</div>
36+
<CreateHeader ActiveProduct="@ActiveProduct" WorkStation="@ActiveWorkStation" />
37+
}
7938

80-
@if (showNotesForStep.ContainsKey(step.Id) && showNotesForStep[step.Id] && logStep != null)
39+
<div class="d-inline-flex gap-4 align-items-center flex-sm-wrap">
40+
<div class="">
41+
<p class="mb-0">
42+
@if (IsSaved)
8143
{
82-
<div class="col-12">
83-
@if (logStep != null)
84-
{
85-
<InputTextArea @bind-Value="logStep.Notes" />
86-
}
87-
else
88-
{
89-
<p>Loading...</p>
90-
}
91-
</div>
44+
<span class="badge text-bg-success p-2">Saved</span>
9245
}
93-
46+
else
47+
{
48+
<span class="badge text-bg-danger p-2">Unsaved</span>
49+
}
50+
</p>
51+
</div>
52+
@if (!IsEditMode)
53+
{
54+
<div>
55+
<button type="button" disabled="@(WorkInstructionStatus is Status.InProgress or Status.Completed)" class="btn btn-warning" @onclick="HandleResetConfiguration">Reset Configuration</button>
9456
</div>
95-
96-
</li>
97-
}
98-
</ul>
99-
}
100-
</div>
101-
</div>
102-
103-
<div class="form-group">
104-
<button type="submit" class="btn btn-primary">Save</button>
105-
</div>
106-
</EditForm>
107-
108-
@code {
109-
[Parameter]
110-
public int? logId { get; set; }
111-
protected string Title = "Add";
112-
protected ProductionLog ProductionLog = new();
113-
private Dictionary<int, bool> showNotesForStep = new();
114-
115-
private bool ShowOptionalNotesField { get; set; } = false;
116-
private List<WorkInstruction>? WorkInstructions { get; set; }
117-
private WorkInstruction? ActiveWorkInstruction { get; set; }
118-
private int? _selectedWorkInstructionId;
119-
private int? SelectedWorkInstructionId
120-
{
121-
get => _selectedWorkInstructionId;
122-
set
123-
{
124-
if (_selectedWorkInstructionId == value) return;
125-
_selectedWorkInstructionId = value;
126-
if (value.HasValue)
127-
{
128-
_ = LoadActiveWorkInstruction(value.Value);
129-
}
130-
}
131-
}
132-
133-
private async Task LoadActiveWorkInstruction(int id)
134-
{
135-
ActiveWorkInstruction = await WorkInstructionService.GetByIdAsync(id);
136-
137-
if (ActiveWorkInstruction != null)
138-
{
139-
// For each step in the work instruction
140-
foreach (var step in ActiveWorkInstruction.Steps)
141-
{
142-
// Try to find existing log step
143-
var existingLogStep = ProductionLog.LogSteps
144-
.FirstOrDefault(ls => ls.WorkInstructionStepId == step.Id);
145-
146-
if (existingLogStep != null)
147-
{
148-
// Sync the step with existing log data
149-
step.Success = existingLogStep.Success;
150-
step.SubmitTime = existingLogStep.SubmitTime;
151-
}
152-
else if (!ProductionLog.LogSteps.Any())
57+
}
58+
</div>
59+
60+
</div>
61+
62+
@if (ActiveWorkInstruction != null && ActiveProduct != null)
15363
{
154-
// For new logs, initialize first step
155-
if (ActiveWorkInstruction.Steps.First() == step)
156-
{
157-
step.SubmitTime = DateTimeOffset.UtcNow;
158-
}
64+
<WorkInstructionStepList ActiveWorkInstruction="@ActiveWorkInstruction" ProductionLog="ProductionLog" OnStepCompleted="@(async (args) => await OnStepCompleted(args.Item1, args.Item2))" IsEditMode="@IsEditMode"/>
15965
}
160-
}
161-
}
162-
163-
StateHasChanged();
164-
}
165-
166-
167-
168-
protected override async Task OnInitializedAsync()
169-
{
170-
WorkInstructions = await WorkInstructionService.GetAllAsync();
171-
172-
if (logId.HasValue && logId.Value != 0)
173-
{
174-
await LoadExistingLog(logId.Value);
175-
}
176-
177-
if (ActiveWorkInstruction != null)
178-
{
179-
foreach (var step in ActiveWorkInstruction.Steps)
180-
{
181-
showNotesForStep[step.Id] = false;
182-
}
183-
}
184-
}
185-
186-
private async Task LoadExistingLog(int id)
187-
{
188-
var existingProductionLog = await ProductionLogService.GetByIdAsync(id);
189-
if (existingProductionLog != null)
190-
{
191-
Title = "Edit";
192-
ProductionLog = existingProductionLog;
193-
194-
if (ProductionLog.WorkInstruction != null)
195-
{
196-
SelectedWorkInstructionId = ProductionLog.WorkInstruction.Id;
197-
}
198-
}
199-
else
200-
{
201-
Console.WriteLine($"Production log with ID {id} not found.");
202-
}
203-
}
20466

205-
206-
207-
protected async void HandleSubmit()
208-
{
209-
if (ActiveWorkInstruction == null)
210-
{
211-
Console.WriteLine("No Work Instruction selected.");
212-
return;
213-
}
67+
</div>
68+
<div class="d-flex justify-content-center mt-4 gap-4">
21469

215-
var currentTime = DateTimeOffset.UtcNow;
216-
foreach (var step in ActiveWorkInstruction.Steps)
217-
{
218-
var logStep = ProductionLog.LogSteps.FirstOrDefault(ls => ls.WorkInstructionStepId == step.Id);
219-
if (logStep == null) continue;
220-
logStep.Success = step.Success;
221-
logStep.SubmitTime = step.SubmitTime;
222-
}
223-
224-
225-
ProductionLog.WorkInstruction = ActiveWorkInstruction;
226-
227-
if (logId.HasValue)
228-
{
229-
// Update existing log
230-
ProductionLog.LastModifiedOn = currentTime;
231-
await ProductionLogService.UpdateAsync(ProductionLog);
232-
}
233-
else
234-
{
235-
// Create new log
236-
ProductionLog.CreatedOn = currentTime;
237-
ProductionLog.LastModifiedOn = currentTime;
238-
ProductionLogService.Create(ProductionLog);
239-
}
240-
241-
Cancel();
242-
}
243-
244-
private void OnStepCompleted(Step step, ChangeEventArgs e, bool success)
245-
{
246-
if (ActiveWorkInstruction?.Steps == null) return;
247-
248-
var currentTime = DateTimeOffset.UtcNow;
249-
250-
if (success)
251-
{
252-
step.Success = true;
253-
step.SubmitTime = currentTime;
254-
}
255-
else
256-
{
257-
step.Success = false;
258-
step.SubmitTime = currentTime;
259-
showNotesForStep[step.Id] = true;
260-
}
70+
@if (IsEditMode)
71+
{
72+
<div class="d-flex align-items-center form-control">
73+
<label for="timePickerSubmit" class="me-2">Submit Time:</label>
74+
<div id="timePickerSubmit">
75+
<TimePicker @bind-Time="ProductionLog.SubmitTime"
76+
Min="@GetLatestStepTime()" Max="null" CssClass="mb-0"/>
77+
</div>
78+
</div>
79+
}
26180

262-
StateHasChanged();
263-
}
264-
265-
private void Cancel()
266-
{
267-
NavigationManager.NavigateTo("/production-log");
268-
}
269-
}
81+
<div class="mb-4">
82+
<button disabled="@(WorkInstructionStatus is Status.NotStarted or Status.InProgress)" type="submit" class="btn btn-primary">Save</button>
83+
</div>
84+
85+
</div>
86+
</EditForm>
87+
</ChildContent>
88+
<ErrorContent Context="ex">
89+
<div class="alert alert-danger" role="alert">
90+
An error occurred: @ex.Message
91+
</div>
92+
</ErrorContent>
93+
</ErrorBoundary>

0 commit comments

Comments
 (0)