Refactor and enhance SenderPage grid and UI behavior
Refactored the `DxGrid` component in `SenderPage.razor` to improve readability, maintainability, and user experience. Added new grid properties like `HighlightRowOnHover` and `DetailExpandButtonDisplayMode`. Simplified and reorganized column and template structures. Enhanced detail row behavior to handle row expansion and collapse more intuitively. Updated receiver and history displays with progress bars, badges, and improved styling. Performed code cleanup by removing redundant blocks, consolidating logic, and eliminating unused variables. Refactored `ThemeService.LoadFromServerAsync` for better readability. Made minor adjustments to the `CreateEnvelopeWizardPopup` configuration and improved general UI elements for better alignment, spacing, and styling.
This commit is contained in:
@@ -223,215 +223,223 @@
|
||||
|
||||
<div class="sender-grid-wrapper">
|
||||
<DxGrid @key="_activeTab"
|
||||
Data="@CurrentGridData"
|
||||
@ref="_grid"
|
||||
KeyFieldName="Id"
|
||||
ShowFilterRow="false"
|
||||
FilterMenuButtonDisplayMode="GridFilterMenuButtonDisplayMode.Always"
|
||||
ShowSearchBox="true"
|
||||
AllowColumnReorder="true"
|
||||
AllowSort="true"
|
||||
ColumnResizeMode="GridColumnResizeMode.ColumnsContainer"
|
||||
PageSize="20"
|
||||
PagerVisible="true"
|
||||
SelectionMode="GridSelectionMode.Single"
|
||||
AllowSelectRowByClick="true"
|
||||
SelectedDataItem="@_selectedEnvelope"
|
||||
SelectedDataItemChanged="@((object o) => _selectedEnvelope = o as EnvelopeDto)"
|
||||
RowClick="OnRowClick"
|
||||
RowDoubleClick="OnRowDoubleClick"
|
||||
CustomizeElement="OnCustomizeElement"
|
||||
LayoutAutoLoading="OnGridLayoutAutoLoading"
|
||||
LayoutAutoSaving="OnGridLayoutAutoSaving"
|
||||
AutoCollapseDetailRow=true>
|
||||
<Columns>
|
||||
<DxGridDataColumn FieldName="Id" Caption="ID"
|
||||
DisplayFormat="0"
|
||||
SortIndex="0"
|
||||
SortOrder="GridColumnSortOrder.Descending">
|
||||
<CellDisplayTemplate Context="cellContext">
|
||||
@((cellContext.DataItem as EnvelopeDto)?.Id)
|
||||
</CellDisplayTemplate>
|
||||
</DxGridDataColumn>
|
||||
<DxGridDataColumn FieldName="Title" Caption="@L("Title", "Titel")">
|
||||
<CellDisplayTemplate Context="cellContext">
|
||||
<strong>@((cellContext.DataItem as EnvelopeDto)?.Title)</strong>
|
||||
</CellDisplayTemplate>
|
||||
</DxGridDataColumn>
|
||||
<DxGridDataColumn FieldName="Status" Caption="@L("Status", "Status")" ExportEnabled="false">
|
||||
<EditSettings>
|
||||
<DxComboBoxSettings Data="@GetStatusFilterItems(CurrentGridData)"
|
||||
ValueFieldName="Value"
|
||||
TextFieldName="Text"
|
||||
SearchMode="ListSearchMode.AutoSearch"
|
||||
SearchFilterCondition="ListSearchFilterCondition.Contains" />
|
||||
</EditSettings>
|
||||
<CellDisplayTemplate Context="cellContext">
|
||||
@{
|
||||
var envelope = cellContext.DataItem as EnvelopeDto;
|
||||
if (envelope != null)
|
||||
{
|
||||
var statusInfo = GetStatusInfo(GetEffectiveEnvelopeStatus(envelope));
|
||||
<div class="status-badge status-badge--@statusInfo.CssClass">
|
||||
<span class="status-dot status-dot--@statusInfo.DotColor"></span>
|
||||
@statusInfo.Label
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</CellDisplayTemplate>
|
||||
</DxGridDataColumn>
|
||||
<DxGridDataColumn FieldName="EnvelopeReceivers" Caption="@L("Receiver", "Empfänger")" ExportEnabled="false">
|
||||
<CellDisplayTemplate Context="cellContext">
|
||||
@{
|
||||
var envelope = cellContext.DataItem as EnvelopeDto;
|
||||
if (envelope != null)
|
||||
{
|
||||
var receivers = envelope.EnvelopeReceivers?.ToList() ?? [];
|
||||
var signed = GetSignedReceiverCount(envelope);
|
||||
var total = receivers.Count;
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<span style="font-size: 0.875rem; color: #6b7280;">
|
||||
@signed / @total @L("Signed", "unterschrieben")
|
||||
</span>
|
||||
@if (total > 0)
|
||||
{
|
||||
<div style="flex: 1; min-width: 60px; max-width: 120px; height: 6px; background: #e5e7eb; border-radius: 3px; overflow: hidden;">
|
||||
<div style="height: 100%; background: linear-gradient(90deg, #81c784 0%, #66bb6a 100%); width: @((signed * 100.0 / total).ToString("F0"))%;"></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</CellDisplayTemplate>
|
||||
</DxGridDataColumn>
|
||||
<DxGridDataColumn FieldName="EnvelopeTypeTitle" Caption="@L("Type", "Typ")"
|
||||
Width="120px" AllowSort="true" />
|
||||
<DxGridDataColumn FieldName="AddedWhen" Caption="@L("Created", "Erstellt")"
|
||||
DisplayFormat="{0:dd.MM.yyyy}" Width="110px" AllowSort="true" />
|
||||
<DxGridDataColumn FieldName="ChangedWhen" Caption="@L("ChangedAt", "Geändert am")"
|
||||
DisplayFormat="{0:dd.MM.yyyy}" Width="110px" AllowSort="true" />
|
||||
</Columns>
|
||||
<DetailRowTemplate Context="detailContext">
|
||||
<div style="padding: 1rem; background: #f9fafb;">
|
||||
<h6 style="font-weight: 600; color: #374151; margin-bottom: 0.75rem;">@L("Receiver", "Empfänger")</h6>
|
||||
Data="@CurrentGridData"
|
||||
@ref="_grid"
|
||||
KeyFieldName="Id"
|
||||
ShowFilterRow="false"
|
||||
FilterMenuButtonDisplayMode="GridFilterMenuButtonDisplayMode.Always"
|
||||
ShowSearchBox="true"
|
||||
AllowColumnReorder="true"
|
||||
AllowSort="true"
|
||||
ColumnResizeMode="GridColumnResizeMode.ColumnsContainer"
|
||||
PageSize="20"
|
||||
PagerVisible="true"
|
||||
SelectionMode="GridSelectionMode.Single"
|
||||
AllowSelectRowByClick="true"
|
||||
SelectedDataItem="@_selectedEnvelope"
|
||||
SelectedDataItemChanged="@((object o) => _selectedEnvelope = o as EnvelopeDto)"
|
||||
RowClick="OnRowClick"
|
||||
RowDoubleClick="OnRowDoubleClick"
|
||||
CustomizeElement="OnCustomizeElement"
|
||||
LayoutAutoLoading="OnGridLayoutAutoLoading"
|
||||
LayoutAutoSaving="OnGridLayoutAutoSaving"
|
||||
HighlightRowOnHover="true"
|
||||
AutoCollapseDetailRow=true
|
||||
DetailExpandButtonDisplayMode="GridDetailExpandButtonDisplayMode.Auto">
|
||||
<Columns>
|
||||
<DxGridDataColumn FieldName="Id" Caption="ID"
|
||||
DisplayFormat="0"
|
||||
SortIndex="0"
|
||||
SortOrder="GridColumnSortOrder.Descending">
|
||||
<CellDisplayTemplate Context="cellContext">
|
||||
@((cellContext.DataItem as EnvelopeDto)?.Id)
|
||||
</CellDisplayTemplate>
|
||||
</DxGridDataColumn>
|
||||
<DxGridDataColumn FieldName="Title" Caption="@L("Title", "Titel")">
|
||||
<CellDisplayTemplate Context="cellContext">
|
||||
<strong>@((cellContext.DataItem as EnvelopeDto)?.Title)</strong>
|
||||
</CellDisplayTemplate>
|
||||
</DxGridDataColumn>
|
||||
<DxGridDataColumn FieldName="Status" Caption="@L("Status", "Status")" ExportEnabled="false">
|
||||
<EditSettings>
|
||||
<DxComboBoxSettings Data="@GetStatusFilterItems(CurrentGridData)"
|
||||
ValueFieldName="Value"
|
||||
TextFieldName="Text"
|
||||
SearchMode="ListSearchMode.AutoSearch"
|
||||
SearchFilterCondition="ListSearchFilterCondition.Contains" />
|
||||
</EditSettings>
|
||||
<CellDisplayTemplate Context="cellContext">
|
||||
@{
|
||||
var envelope = detailContext.DataItem as EnvelopeDto;
|
||||
if (envelope?.EnvelopeReceivers?.Any() == true)
|
||||
var envelope = cellContext.DataItem as EnvelopeDto;
|
||||
if (envelope != null)
|
||||
{
|
||||
<div style="display: flex; flex-direction: column; gap: 0.5rem;">
|
||||
@foreach (var receiver in envelope.EnvelopeReceivers)
|
||||
{
|
||||
<div style="display: flex; align-items: center; gap: 1rem; padding: 0.5rem; background: white; border-radius: 6px; border: 1px solid #e5e7eb;">
|
||||
@{
|
||||
var isRejected = IsReceiverRejected(envelope, receiver);
|
||||
var isSigned = IsReceiverSigned(envelope, receiver);
|
||||
var accessCode = receiver.AccessCode;
|
||||
var hasAccessCode = !string.IsNullOrWhiteSpace(accessCode);
|
||||
var hasReceiverEnvelopeUrl = CanOpenReceiverEnvelopeUrl(envelope, receiver);
|
||||
}
|
||||
<span class="receiver-badge receiver-badge--@(isRejected ? "unsigned" : (isSigned ? "signed" : "unsigned"))" style="min-width: 100px;">
|
||||
@if (isRejected)
|
||||
{
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z" />
|
||||
</svg>
|
||||
<span>@GetStatusLabel(EnvelopeStatus.DocumentRejected)</span>
|
||||
}
|
||||
else if (isSigned)
|
||||
{
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z" />
|
||||
</svg>
|
||||
<span>@L("Signed", "Unterschrieben")</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
|
||||
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" />
|
||||
</svg>
|
||||
<span>@L("Pending", "Ausstehend")</span>
|
||||
}
|
||||
</span>
|
||||
<div style="flex: 1; font-size: 0.875rem;">
|
||||
<strong style="color: #1f2937;">@receiver.Name</strong>
|
||||
<span style="color: #6b7280; margin-left: 0.5rem;">@receiver.Receiver?.EmailAddress</span>
|
||||
</div>
|
||||
<div class="sender-access-code">
|
||||
<span class="sender-access-code__label">@L("AccessCode", "Access code")</span>
|
||||
<div class="sender-access-code__row">
|
||||
<input class="sender-access-code__value"
|
||||
value="@(hasAccessCode ? accessCode : "-")"
|
||||
readonly
|
||||
title="@L("AccessCode", "Access code")" />
|
||||
<button type="button"
|
||||
class="sender-access-code__copy"
|
||||
disabled="@(!hasAccessCode)"
|
||||
@onclick='() => CopyAccessCodeAsync(accessCode)'
|
||||
title="@L("Copy", "Copy")">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path d="M10 1.5A1.5 1.5 0 0 1 11.5 3v1H13A1.5 1.5 0 0 1 14.5 5.5v8A1.5 1.5 0 0 1 13 15H5A1.5 1.5 0 0 1 3.5 13.5V12H3A1.5 1.5 0 0 1 1.5 10.5v-8A1.5 1.5 0 0 1 3 1h7zm.5 2A.5.5 0 0 0 10 3H3a.5.5 0 0 0-.5.5v7A.5.5 0 0 0 3 11h.5V5.5A1.5 1.5 0 0 1 5 4h5.5v-.5zM5 5a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-8A.5.5 0 0 0 13 5H5z"/>
|
||||
</svg>
|
||||
</button>
|
||||
@if (_canUseReceiverEnvelopeUrl)
|
||||
{
|
||||
<button type="button"
|
||||
class="sender-access-code__copy"
|
||||
disabled="@(!hasReceiverEnvelopeUrl)"
|
||||
@onclick='() => OpenReceiverEnvelopeUrlAsync(envelope, receiver)'
|
||||
title="@L("Open", "Open")">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M6.364 13.5a1.5 1.5 0 0 1-1.5-1.5V4a1.5 1.5 0 0 1 1.5-1.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-4a.5.5 0 0 1 1 0v4a1.5 1.5 0 0 1-1.5 1.5h-8z"/>
|
||||
<path fill-rule="evenodd" d="M8.5 1a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-1 0V2.707L8.854 7.354a.5.5 0 1 1-.708-.708L12.793 2H9a.5.5 0 0 1-.5-.5z"/>
|
||||
</svg>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p style="color: #9ca3af; font-size: 0.875rem; margin: 0;">@L("Sender_NoReceivers", "Keine Empfänger")</p>
|
||||
var statusInfo = GetStatusInfo(GetEffectiveEnvelopeStatus(envelope));
|
||||
<div class="status-badge status-badge--@statusInfo.CssClass">
|
||||
<span class="status-dot status-dot--@statusInfo.DotColor"></span>
|
||||
@statusInfo.Label
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
<h6 style="font-weight: 600; color: #374151; margin: 1rem 0 0.75rem;">@L("History", "Historie")</h6>
|
||||
</CellDisplayTemplate>
|
||||
</DxGridDataColumn>
|
||||
<DxGridDataColumn FieldName="EnvelopeReceivers" Caption="@L("Receiver", "Empfänger")" ExportEnabled="false">
|
||||
<CellDisplayTemplate Context="cellContext">
|
||||
@{
|
||||
var historyEntries = envelope is null
|
||||
? Enumerable.Empty<HistoryDto>()
|
||||
: GetOrderedHistories(envelope);
|
||||
if (historyEntries.Any())
|
||||
var envelope = cellContext.DataItem as EnvelopeDto;
|
||||
if (envelope != null)
|
||||
{
|
||||
<div class="sender-history-list">
|
||||
@foreach (var history in historyEntries)
|
||||
var receivers = envelope.EnvelopeReceivers?.ToList() ?? [];
|
||||
var signed = GetSignedReceiverCount(envelope);
|
||||
var total = receivers.Count;
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<span style="font-size: 0.875rem; color: #6b7280;">
|
||||
@signed / @total @L("Signed", "unterschrieben")
|
||||
</span>
|
||||
@if (total > 0)
|
||||
{
|
||||
var statusInfo = GetStatusInfo(history.Status);
|
||||
<div class="sender-history-item">
|
||||
<div class="sender-history-item__left">
|
||||
<div class="status-badge status-badge--@statusInfo.CssClass">
|
||||
<span class="status-dot status-dot--@statusInfo.DotColor"></span>
|
||||
@statusInfo.Label
|
||||
</div>
|
||||
<span class="sender-history-item__actor">@GetHistoryActor(history)</span>
|
||||
</div>
|
||||
<div class="sender-history-item__right">
|
||||
@GetHistoryDate(history).ToString("dd.MM.yyyy HH:mm")
|
||||
</div>
|
||||
<div style="flex: 1; min-width: 60px; max-width: 120px; height: 6px; background: #e5e7eb; border-radius: 3px; overflow: hidden;">
|
||||
<div style="height: 100%; background: linear-gradient(90deg, #81c784 0%, #66bb6a 100%); width: @((signed * 100.0 / total).ToString("F0"))%;"></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p style="color: #9ca3af; font-size: 0.875rem; margin: 0;">@L("Sender_NoHistory", "Keine Historie vorhanden")</p>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</DetailRowTemplate>
|
||||
</DxGrid>
|
||||
</CellDisplayTemplate>
|
||||
</DxGridDataColumn>
|
||||
<DxGridDataColumn FieldName="EnvelopeTypeTitle" Caption="@L("Type", "Typ")"
|
||||
Width="120px" AllowSort="true" />
|
||||
<DxGridDataColumn FieldName="AddedWhen" Caption="@L("Created", "Erstellt")"
|
||||
DisplayFormat="{0:dd.MM.yyyy}" Width="110px" AllowSort="true" />
|
||||
<DxGridDataColumn FieldName="ChangedWhen" Caption="@L("ChangedAt", "Geändert am")"
|
||||
DisplayFormat="{0:dd.MM.yyyy}" Width="110px" AllowSort="true" />
|
||||
</Columns>
|
||||
<DetailRowTemplate Context="detailContext">
|
||||
<div style="padding: 1rem; background: #f9fafb;">
|
||||
<h6 style="font-weight: 600; color: #374151; margin-bottom: 0.75rem;">@L("Receiver", "Empfänger")</h6>
|
||||
@{
|
||||
var envelope = detailContext.DataItem as EnvelopeDto;
|
||||
if(envelope is not null && _grid is not null)
|
||||
{
|
||||
_grid.SelectDataItem(envelope);
|
||||
// _grid!.SelectedDataItem = envelope!;
|
||||
}
|
||||
|
||||
if (envelope?.EnvelopeReceivers?.Any() == true)
|
||||
{
|
||||
<div style="display: flex; flex-direction: column; gap: 0.5rem;">
|
||||
@foreach (var receiver in envelope.EnvelopeReceivers)
|
||||
{
|
||||
<div style="display: flex; align-items: center; gap: 1rem; padding: 0.5rem; background: white; border-radius: 6px; border: 1px solid #e5e7eb;">
|
||||
@{
|
||||
var isRejected = IsReceiverRejected(envelope, receiver);
|
||||
var isSigned = IsReceiverSigned(envelope, receiver);
|
||||
var accessCode = receiver.AccessCode;
|
||||
var hasAccessCode = !string.IsNullOrWhiteSpace(accessCode);
|
||||
var hasReceiverEnvelopeUrl = CanOpenReceiverEnvelopeUrl(envelope, receiver);
|
||||
}
|
||||
<span class="receiver-badge receiver-badge--@(isRejected ? "unsigned" : (isSigned ? "signed" : "unsigned"))" style="min-width: 100px;">
|
||||
@if (isRejected)
|
||||
{
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z" />
|
||||
</svg>
|
||||
<span>@GetStatusLabel(EnvelopeStatus.DocumentRejected)</span>
|
||||
}
|
||||
else if (isSigned)
|
||||
{
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z" />
|
||||
</svg>
|
||||
<span>@L("Signed", "Unterschrieben")</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
|
||||
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" />
|
||||
</svg>
|
||||
<span>@L("Pending", "Ausstehend")</span>
|
||||
}
|
||||
</span>
|
||||
<div style="flex: 1; font-size: 0.875rem;">
|
||||
<strong style="color: #1f2937;">@receiver.Name</strong>
|
||||
<span style="color: #6b7280; margin-left: 0.5rem;">@receiver.Receiver?.EmailAddress</span>
|
||||
</div>
|
||||
<div class="sender-access-code">
|
||||
<span class="sender-access-code__label">@L("AccessCode", "Access code")</span>
|
||||
<div class="sender-access-code__row">
|
||||
<input class="sender-access-code__value"
|
||||
value="@(hasAccessCode ? accessCode : "-")"
|
||||
readonly
|
||||
title="@L("AccessCode", "Access code")" />
|
||||
<button type="button"
|
||||
class="sender-access-code__copy"
|
||||
disabled="@(!hasAccessCode)"
|
||||
@onclick='() => CopyAccessCodeAsync(accessCode)'
|
||||
title="@L("Copy", "Copy")">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path d="M10 1.5A1.5 1.5 0 0 1 11.5 3v1H13A1.5 1.5 0 0 1 14.5 5.5v8A1.5 1.5 0 0 1 13 15H5A1.5 1.5 0 0 1 3.5 13.5V12H3A1.5 1.5 0 0 1 1.5 10.5v-8A1.5 1.5 0 0 1 3 1h7zm.5 2A.5.5 0 0 0 10 3H3a.5.5 0 0 0-.5.5v7A.5.5 0 0 0 3 11h.5V5.5A1.5 1.5 0 0 1 5 4h5.5v-.5zM5 5a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-8A.5.5 0 0 0 13 5H5z"/>
|
||||
</svg>
|
||||
</button>
|
||||
@if (_canUseReceiverEnvelopeUrl)
|
||||
{
|
||||
<button type="button"
|
||||
class="sender-access-code__copy"
|
||||
disabled="@(!hasReceiverEnvelopeUrl)"
|
||||
@onclick='() => OpenReceiverEnvelopeUrlAsync(envelope, receiver)'
|
||||
title="@L("Open", "Open")">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M6.364 13.5a1.5 1.5 0 0 1-1.5-1.5V4a1.5 1.5 0 0 1 1.5-1.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5v-4a.5.5 0 0 1 1 0v4a1.5 1.5 0 0 1-1.5 1.5h-8z"/>
|
||||
<path fill-rule="evenodd" d="M8.5 1a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-1 0V2.707L8.854 7.354a.5.5 0 1 1-.708-.708L12.793 2H9a.5.5 0 0 1-.5-.5z"/>
|
||||
</svg>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p style="color: #9ca3af; font-size: 0.875rem; margin: 0;">@L("Sender_NoReceivers", "Keine Empfänger")</p>
|
||||
}
|
||||
}
|
||||
|
||||
<h6 style="font-weight: 600; color: #374151; margin: 1rem 0 0.75rem;">@L("History", "Historie")</h6>
|
||||
@{
|
||||
var historyEntries = envelope is null
|
||||
? Enumerable.Empty<HistoryDto>()
|
||||
: GetOrderedHistories(envelope);
|
||||
if (historyEntries.Any())
|
||||
{
|
||||
<div class="sender-history-list">
|
||||
@foreach (var history in historyEntries)
|
||||
{
|
||||
var statusInfo = GetStatusInfo(history.Status);
|
||||
<div class="sender-history-item">
|
||||
<div class="sender-history-item__left">
|
||||
<div class="status-badge status-badge--@statusInfo.CssClass">
|
||||
<span class="status-dot status-dot--@statusInfo.DotColor"></span>
|
||||
@statusInfo.Label
|
||||
</div>
|
||||
<span class="sender-history-item__actor">@GetHistoryActor(history)</span>
|
||||
</div>
|
||||
<div class="sender-history-item__right">
|
||||
@GetHistoryDate(history).ToString("dd.MM.yyyy HH:mm")
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p style="color: #9ca3af; font-size: 0.875rem; margin: 0;">@L("Sender_NoHistory", "Keine Historie vorhanden")</p>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</DetailRowTemplate>
|
||||
</DxGrid>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -440,9 +448,9 @@
|
||||
</div>
|
||||
|
||||
<CreateEnvelopeWizardPopup Visible="@_createWizardVisible"
|
||||
VisibleChanged="OnCreateWizardVisibleChangedAsync"
|
||||
EnvelopeTypes="@_envelopeTypes"
|
||||
StartEditorRequested="StartEditorFromWizardAsync" />
|
||||
VisibleChanged="OnCreateWizardVisibleChangedAsync"
|
||||
EnvelopeTypes="@_envelopeTypes"
|
||||
StartEditorRequested="StartEditorFromWizardAsync" />
|
||||
|
||||
@* ── PDF Vorschau Popup ────────────────────────────────────────────────── *@
|
||||
<DxPopup @bind-Visible="@_previewVisible"
|
||||
@@ -622,8 +630,8 @@
|
||||
// Fan out all independent post-auth calls in parallel to reduce initial load time.
|
||||
var themeTask = Task.Run(async () =>
|
||||
{
|
||||
try { await ThemeService.LoadFromServerAsync(); }
|
||||
catch { /* swallow — default theme remains active */ }
|
||||
try { await ThemeService.LoadFromServerAsync(); }
|
||||
catch { /* swallow — default theme remains active */ }
|
||||
});
|
||||
|
||||
var featureTask = EnvelopeReceiverService.GetReceiverEnvelopeUrlFeatureEnabledAsync();
|
||||
@@ -1080,13 +1088,19 @@
|
||||
var clicked = e.Grid.GetDataItem(e.VisibleIndex) as EnvelopeDto;
|
||||
if (clicked == null) return;
|
||||
|
||||
if (_selectedEnvelope?.Id == clicked.Id)
|
||||
if (e.Grid.IsDetailRowExpanded(e.VisibleIndex))
|
||||
{
|
||||
// Same row clicked again → deselect
|
||||
// Already expanded → collapse and deselect
|
||||
e.Grid.CollapseDetailRow(e.VisibleIndex);
|
||||
_selectedEnvelope = null;
|
||||
e.Grid.DeselectDataItem(clicked);
|
||||
}
|
||||
// Different row: @bind-SelectedDataItem already updated _selectedEnvelope
|
||||
else
|
||||
{
|
||||
// Collapsed → expand and select
|
||||
e.Grid.SelectDataItem(clicked);
|
||||
e.Grid.ExpandDetailRow(e.VisibleIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Double-click: select the row and open preview popup
|
||||
|
||||
Reference in New Issue
Block a user