Iniziata creazione pagina contatti

This commit is contained in:
2025-06-20 08:55:30 +02:00
parent 4608c6764b
commit 51a4c7a971
24 changed files with 896 additions and 125 deletions

View File

@@ -1,9 +1,14 @@
@page "/Notifications"
@attribute [Authorize]
@using Template.Shared.Components.Layout
@using Template.Shared.Components.SingleElements
<HeaderLayout Title="Notifiche" />
<div class="container">
<NoDataAvailable Text="Nessuna notifica meno recente" />
</div>
@code {
}

View File

@@ -10,113 +10,118 @@
<HeaderLayout BackTo="Indietro" Back="true" BackOnTop="true" Title="Profilo" ShowProfile="false"/>
<div class="container content">
<div class="container-primary-info">
<div class="section-primary-info">
<MudAvatar Style="height: 70px; width: 70px; font-size: 2rem; font-weight: bold" Color="Color.Secondary">
@UtilityString.ExtractInitials(UserSession.User.Fullname)
</MudAvatar>
@if (IsLoggedIn)
{
<div class="container content">
<div class="container-primary-info">
<div class="section-primary-info">
<MudAvatar Style="height: 70px; width: 70px; font-size: 2rem; font-weight: bold" Color="Color.Secondary">
@UtilityString.ExtractInitials(UserSession.User.Fullname)
</MudAvatar>
<div class="personal-info">
<span class="info-nome">@UserSession.User.Fullname</span>
@if (UserSession.User.KeyGroup is not null)
{
<span class="info-section">@(((KeyGroupEnum)UserSession.User.KeyGroup).ConvertToHumanReadable())</span>
}
</div>
</div>
<div class="divider"></div>
<div class="section-info">
<div class="section-personal-info">
<div>
<span class="info-title">Telefono</span>
<span class="info-text">000 0000000</span> @*Todo: to implement*@
</div>
<div>
<span class="info-title">Status</span>
@if (NetworkService.IsNetworkAvailable())
<div class="personal-info">
<span class="info-nome">@UserSession.User.Fullname</span>
@if (UserSession.User.KeyGroup is not null)
{
<div class="status online">
<i class="ri-wifi-line"></i>
<span>Online</span>
</div>
}
else
{
<div class="status offline">
<i class="ri-wifi-off-line"></i>
<span>Offline</span>
</div>
<span class="info-section">@(((KeyGroupEnum)UserSession.User.KeyGroup).ConvertToHumanReadable())</span>
}
</div>
</div>
<div class="section-personal-info">
<div>
<span class="info-title">E-mail</span>
<span class="info-text">
@if (string.IsNullOrEmpty(UserSession.User.Email))
<div class="divider"></div>
<div class="section-info">
<div class="section-personal-info">
<div>
<span class="info-title">Telefono</span>
<span class="info-text">000 0000000</span> @*Todo: to implement*@
</div>
<div>
<span class="info-title">Status</span>
@if (NetworkService.IsNetworkAvailable())
{
@("Nessuna mail configurata")
<div class="status online">
<i class="ri-wifi-line"></i>
<span>Online</span>
</div>
}
else
{
@UserSession.User.Email
<div class="status offline">
<i class="ri-wifi-off-line"></i>
<span>Offline</span>
</div>
}
</span>
</div>
</div>
<div>
<span class="info-title">Ultima sincronizzazione</span>
<span class="info-text">@LastSync.ToString("g")</span>
<div class="section-personal-info">
<div>
<span class="info-title">E-mail</span>
<span class="info-text">
@if (string.IsNullOrEmpty(UserSession.User.Email))
{
@("Nessuna mail configurata")
}
else
{
@UserSession.User.Email
}
</span>
</div>
<div>
<span class="info-title">Ultima sincronizzazione</span>
<span class="info-text">@LastSync.ToString("g")</span>
</div>
</div>
</div>
</div>
<div class="container-button">
<MudButton Class="button-settings green-icon"
FullWidth="true"
StartIcon="@Icons.Material.Outlined.Sync"
Size="Size.Medium"
OnClick="() => UpdateDb(true)"
Variant="Variant.Outlined">
Sincronizza
</MudButton>
<div class="divider"></div>
<MudButton Class="button-settings red-icon"
FullWidth="true"
StartIcon="@Icons.Material.Outlined.Sync"
Size="Size.Medium"
OnClick="() => UpdateDb()"
Variant="Variant.Outlined">
Ripristina dati
</MudButton>
</div>
<div class="container-button">
<MudButton Class="button-settings exit"
FullWidth="true"
Color="Color.Error"
Size="Size.Medium"
OnClick="Logout"
Variant="Variant.Outlined">
Esci
</MudButton>
</div>
</div>
<div class="container-button">
<MudButton Class="button-settings green-icon"
FullWidth="true"
StartIcon="@Icons.Material.Outlined.Sync"
Size="Size.Medium"
OnClick="() => UpdateDb(true)"
Variant="Variant.Outlined">
Sincronizza
</MudButton>
<div class="divider"></div>
<MudButton Class="button-settings red-icon"
FullWidth="true"
StartIcon="@Icons.Material.Outlined.Sync"
Size="Size.Medium"
OnClick="() => UpdateDb()"
Variant="Variant.Outlined">
Ripristina dati
</MudButton>
</div>
<div class="container-button">
<MudButton Class="button-settings exit"
FullWidth="true"
Color="Color.Error"
Size="Size.Medium"
OnClick="Logout"
Variant="Variant.Outlined">
Esci
</MudButton>
</div>
</div>
}
@code {
private bool Unavailable { get; set; }
private bool IsLoggedIn { get; set; }
private DateTime LastSync { get; set; }
protected override async Task OnInitializedAsync()
{
IsLoggedIn = await UserSession.IsLoggedIn();
await LoadData();
}
@@ -134,8 +139,12 @@
private void OpenSettings() =>
NavigationManager.NavigateTo("/settings/Profilo");
private void Logout() =>
AuthenticationStateProvider.SignOut();
private async Task Logout()
{
await AuthenticationStateProvider.SignOut();
IsLoggedIn = await UserSession.IsLoggedIn();
StateHasChanged();
}
private void UpdateDb(bool withData = false)
{

View File

@@ -0,0 +1,113 @@
@page "/User/{CodAnag}"
@attribute [Authorize]
@using Template.Shared.Components.Layout
@using Template.Shared.Core.Entity
@using Template.Shared.Core.Interface
@using Template.Shared.Components.Layout.Spinner
@inject IManageDataService ManageData
<HeaderLayout BackTo="Indietro" Back="true" BackOnTop="true" Title="" ShowProfile="false"/>
@if (IsLoading)
{
<SpinnerLayout FullScreen="true"/>
}
else
{
<div class="container content">
<div class="container-primary-info">
<div class="section-primary-info">
<MudAvatar Style="height: 70px; width: 70px; font-size: 2rem; font-weight: bold" Color="Color.Secondary">
@UtilityString.ExtractInitials(Anag.RagSoc)
</MudAvatar>
<div class="personal-info">
<span class="info-nome">@Anag.RagSoc</span>
@if (UserSession.User.KeyGroup is not null)
{
<span class="info-section">@Anag.Indirizzo</span>
<span class="info-section">@($"{Anag.Cap} - {Anag.Citta} ({Anag.Prov})")</span>
}
</div>
</div>
<div class="divider"></div>
<div class="section-info">
<div class="section-personal-info">
<div>
<span class="info-title">Telefono</span>
<span class="info-text">
@if (string.IsNullOrEmpty(Anag.Telefono))
{
@("Nessuna mail configurata")
}
else
{
@Anag.Telefono
}
</span>
</div>
</div>
<div class="section-personal-info">
<div>
<span class="info-title">E-mail</span>
<span class="info-text">
@if (string.IsNullOrEmpty(Anag.EMail))
{
@("Nessuna mail configurata")
}
else
{
@Anag.EMail
}
</span>
</div>
</div>
</div>
</div>
@if (PersRif is { Count: > 0 })
{
<div class="container-pers-rif">
<Virtualize Items="PersRif" Context="person">
<ContactCard Contact="person"/>
</Virtualize>
</div>
}
<div class="container-button">
<MudButton Class="button-settings infoText"
FullWidth="true"
Size="Size.Medium"
Variant="Variant.Outlined">
Aggiungi contatto
</MudButton>
</div>
</div>
}
@code {
[Parameter] public string CodAnag { get; set; }
private AnagClie Anag { get; set; } = new();
private List<VtbCliePersRif>? PersRif { get; set; }
private bool IsLoading { get; set; } = true;
protected override async Task OnInitializedAsync()
{
await LoadData();
}
private async Task LoadData()
{
Anag = (await ManageData.GetTable<AnagClie>(x => x.CodAnag.Equals(CodAnag))).Last();
PersRif = await ManageData.GetTable<VtbCliePersRif>(x => x.CodAnag.Equals(Anag.CodAnag));
IsLoading = false;
StateHasChanged();
}
}

View File

@@ -0,0 +1,142 @@
.container-primary-info {
box-shadow: var(--custom-box-shadow);
width: 100%;
margin-bottom: 2rem;
border-radius: 16px;
}
.container-primary-info .divider {
margin: 0 0 0 7rem;
width: unset;
}
.section-primary-info {
display: flex;
flex-direction: row;
align-items: center;
gap: 1.5rem;
padding: .8rem 1.2rem .4rem;
}
.personal-info {
display: flex;
flex-direction: column;
align-items: flex-start;
line-height: normal;
}
.info-nome {
color: var(--mud-palette-text-primary);
font-weight: 800;
font-size: medium;
}
.info-section {
color: var(--mud-palette-gray-default);
font-size: small;
font-weight: 600;
}
.section-info {
display: flex;
justify-content: space-between;
flex-direction: row;
padding: .4rem 1.2rem .8rem;
}
.section-personal-info {
display: flex;
flex-direction: column;
}
.section-personal-info > div {
display: flex;
flex-direction: column;
line-height: normal;
margin: .25rem 0;
}
.info-title {
color: var(--mud-palette-gray-darker);
font-weight: 800;
}
.info-text {
color: var(--mud-palette-text-secondary);
font-weight: 700;
font-size: small;
}
.content ::deep .user-button { border: 1px solid var(--card-border-color) !important; }
.user-button > i { font-size: large; }
.user-button > span {
font-size: medium;
font-weight: 600;
}
.status { font-weight: 700; }
.status.online { color: var(--mud-palette-success); }
.status.offline { color: var(--mud-palette-error); }
.container-button {
width: 100%;
box-shadow: var(--custom-box-shadow);
padding: .25rem 0;
border-radius: 16px;
}
.container-button .divider {
margin: .5rem 0 .5rem 3rem;
width: unset;
}
.container-button ::deep .button-settings { border: none !important; }
.container-button ::deep .button-settings .mud-icon-root {
border-radius: 6px;
padding: 2px;
min-width: 25px;
min-height: 25px;
}
.container-button ::deep .button-settings.infoText {
color: var(--mud-palette-info);
}
.container-button ::deep .button-settings.green-icon .mud-icon-root {
border: 1px solid var(--mud-palette-success);
background: hsl(from var(--mud-palette-success-lighten) h s 95%);
color: var(--mud-palette-success-darken);
}
.container-button ::deep .button-settings.red-icon .mud-icon-root {
border: 1px solid var(--mud-palette-error);
background: hsl(from var(--mud-palette-error-lighten) h s 95%);
color: var(--mud-palette-error-darken);
}
.container-button ::deep .button-settings .mud-button-label {
justify-content: flex-start;
text-transform: capitalize;
font-size: 1rem;
}
.container-button ::deep .button-settings.exit { padding: 0; }
.container-button ::deep .button-settings.exit .mud-button-label {
justify-content: center;
font-size: 1.1rem;
line-height: normal;
}
.container-pers-rif {
width: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 1rem;
}

View File

@@ -1,13 +1,105 @@
@page "/Users"
@attribute [Authorize]
@using Template.Shared.Components.Layout
@using Template.Shared.Core.Entity
@using Template.Shared.Core.Interface
@inject IManageDataService ManageData
<HeaderLayout Title="Contatti" />
<HeaderLayout Title="Contatti"/>
<div class="container">
<div class="container users">
@if (GroupedUserList?.Count > 0)
{
<div class="input-card clearButton">
<MudTextField T="string?" Placeholder="Cerca..." Variant="Variant.Text" @bind-Value="TextToFilter" OnDebounceIntervalElapsed="FilterUsers" DebounceInterval="500"/>
<MudIconButton Class="closeIcon" Icon="@Icons.Material.Filled.Close" OnClick="() => FilterUsers(true)"/>
</div>
<Virtualize Items="FilteredGroupedUserList" Context="item">
@if (item.ShowHeader)
{
<div class="letter-header">@item.HeaderLetter</div>
}
<UserCard User="item.User"/>
</Virtualize>
}
</div>
@code {
private List<UserDisplayItem> GroupedUserList { get; set; } = [];
private List<UserDisplayItem> FilteredGroupedUserList { get; set; } = [];
private string? TextToFilter { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await LoadData();
StateHasChanged();
}
}
private async Task LoadData()
{
var users = await ManageData.GetTable<AnagClie>(x => x.FlagStato.Equals("A"));
var sortedUsers = users
.Where(u => !string.IsNullOrWhiteSpace(u.RagSoc))
.OrderBy(u =>
{
var firstChar = char.ToUpper(u.RagSoc[0]);
return char.IsLetter(firstChar) ? firstChar.ToString() : "ZZZ";
})
.ThenBy(u => u.RagSoc)
.ToList();
GroupedUserList = [];
string? lastHeader = null;
foreach (var user in sortedUsers)
{
var firstChar = char.ToUpper(user.RagSoc[0]);
var currentLetter = char.IsLetter(firstChar) ? firstChar.ToString() : "#";
var showHeader = currentLetter != lastHeader;
lastHeader = currentLetter;
GroupedUserList.Add(new UserDisplayItem
{
User = user,
ShowHeader = showHeader,
HeaderLetter = currentLetter
});
}
FilterUsers(true);
}
private class UserDisplayItem
{
public required AnagClie User { get; set; }
public bool ShowHeader { get; set; }
public string? HeaderLetter { get; set; }
}
private void FilterUsers() => FilterUsers(false);
private void FilterUsers(bool clearFilter)
{
if (clearFilter)
{
TextToFilter = null;
FilteredGroupedUserList = GroupedUserList;
StateHasChanged();
return;
}
if (TextToFilter == null) return;
FilteredGroupedUserList = GroupedUserList.FindAll(x => x.User.RagSoc.Contains(TextToFilter, StringComparison.OrdinalIgnoreCase));
StateHasChanged();
}
}

View File

@@ -0,0 +1,22 @@
.users {
display: flex;
gap: 1rem;
overflow-y: auto;
flex-direction: column;
-ms-overflow-style: none;
scrollbar-width: none;
padding-bottom: 70px;
height: 100%;
}
.users .divider {
margin: .1rem 0;
margin-left: 3rem;
}
.users .input-card { margin: 0 !important; }
.letter-header {
border-bottom: 1px solid var(--card-border-color);
font-weight: bolder;
}