generated from Integry/Template_NetMauiBlazorHybrid
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dd115180f1 | |||
| 8a6cfff93f | |||
| da9abd5901 | |||
| 0757980e5d | |||
| f5ee19515c | |||
| f4d62885fb | |||
| 88d145c1ae | |||
| 2be9031b15 | |||
| 26c378ad70 | |||
| bba1004f42 | |||
| aaa0418924 | |||
| 66ea493cfa |
9
.idea/.idea.ConSegna/.idea/libraries/androidx_lifecycle_lifecycle_common_java8.xml
generated
Normal file
9
.idea/.idea.ConSegna/.idea/libraries/androidx_lifecycle_lifecycle_common_java8.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="androidx.lifecycle.lifecycle-common-java8">
|
||||
<CLASSES>
|
||||
<root url="jar://$USER_HOME$/.nuget/packages/xamarin.androidx.lifecycle.common.java8/2.8.7.2/jar/androidx.lifecycle.lifecycle-common-java8.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/.idea.ConSegna/.idea/libraries/org_jetbrains_kotlin_kotlin_stdlib_jdk8_2_0_0.xml
generated
Normal file
9
.idea/.idea.ConSegna/.idea/libraries/org_jetbrains_kotlin_kotlin_stdlib_jdk8_2_0_0.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="org.jetbrains.kotlin.kotlin-stdlib-jdk8-2.0.0">
|
||||
<CLASSES>
|
||||
<root url="jar://$USER_HOME$/.nuget/packages/xamarin.kotlin.stdlib.jdk8/2.0.0/jar/org.jetbrains.kotlin.kotlin-stdlib-jdk8-2.0.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
10
.idea/.idea.ConSegna/.idea/libraries/playservicesbasement_18_7_0.xml
generated
Normal file
10
.idea/.idea.ConSegna/.idea/libraries/playservicesbasement_18_7_0.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<component name="libraryTable">
|
||||
<library name="playservicesbasement-18.7.0">
|
||||
<CLASSES>
|
||||
<root url="file://$USER_HOME$/AppData/Local/Temp/JetBrains/xamarinAarPackages/playservicesbasement-18.7.0/classes.jar" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Temp/JetBrains/xamarinAarPackages/playservicesbasement-18.7.0/res" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/.idea.ConSegna/.idea/libraries/playservicestasks_18_3_0.xml
generated
Normal file
9
.idea/.idea.ConSegna/.idea/libraries/playservicestasks_18_3_0.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="playservicestasks-18.3.0">
|
||||
<CLASSES>
|
||||
<root url="file://$USER_HOME$/AppData/Local/Temp/JetBrains/xamarinAarPackages/playservicestasks-18.3.0/classes.jar" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
@@ -1,7 +1,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ConSegna.Maui.Services.Logger;
|
||||
namespace ConSegna.Maui.Core.Logger;
|
||||
|
||||
public class FileLogger : ILogger
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ConSegna.Maui.Services.Logger;
|
||||
namespace ConSegna.Maui.Core.Logger;
|
||||
|
||||
public class FileLoggerProvider(string path, string fileName) : ILoggerProvider
|
||||
{
|
||||
@@ -1,12 +1,15 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.RegularExpressions;
|
||||
using ConSegna.Shared.Core.Dto;
|
||||
using ConSegna.Shared.Core.Dto;
|
||||
using ConSegna.Shared.Core.Helpers;
|
||||
using ConSegna.Shared.Core.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ConSegna.Maui.Services;
|
||||
namespace ConSegna.Maui.Core.Services;
|
||||
|
||||
public class DataStorage(LocalDbService localDb, ILogger<DataStorage> logger) : IDataStorage
|
||||
public class DataStorage(
|
||||
LocalDbService localDb,
|
||||
ILogger<DataStorage> logger,
|
||||
IUtilityFile utilityFile
|
||||
) : IDataStorage
|
||||
{
|
||||
public Task<List<DatiClientiDTO>> RetrieveDatiClienti() =>
|
||||
localDb.RetrieveDatiClienti();
|
||||
@@ -192,19 +195,7 @@ public class DataStorage(LocalDbService localDb, ILogger<DataStorage> logger) :
|
||||
var filePath = Path.Combine(targetDirectory, file.Name);
|
||||
if (!File.Exists(filePath)) continue;
|
||||
|
||||
const string pattern = @".*_(\d{6})_.*";
|
||||
var match = Regex.Match(file.Name, pattern);
|
||||
DateTime? dataToCheck = null;
|
||||
|
||||
if (match.Success &&
|
||||
DateTime.TryParseExact(
|
||||
match.Groups[1].Value,
|
||||
"yyMMdd",
|
||||
null,
|
||||
System.Globalization.DateTimeStyles.None, out var date))
|
||||
{
|
||||
dataToCheck = date;
|
||||
}
|
||||
var dataToCheck = utilityFile.DetectDataDocFromFileName(file.Name);
|
||||
|
||||
if (dataToCheck == null) continue;
|
||||
if (dataToCheck > twoWeeksAgo) continue;
|
||||
@@ -219,4 +210,86 @@ public class DataStorage(LocalDbService localDb, ILogger<DataStorage> logger) :
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetReceiptDirectoryPath()
|
||||
{
|
||||
var appDataPath = FileSystem.AppDataDirectory;
|
||||
var targetDirectory = Path.Combine(appDataPath, "receipts");
|
||||
|
||||
if (!Directory.Exists(targetDirectory))
|
||||
Directory.CreateDirectory(targetDirectory);
|
||||
|
||||
return targetDirectory;
|
||||
}
|
||||
|
||||
private static string GetReceiptFilePath(string fileName)
|
||||
{
|
||||
var targetDirectory = GetReceiptDirectoryPath();
|
||||
var filePath = Path.Combine(targetDirectory, fileName);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
using var _ = File.Create(filePath);
|
||||
}
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public List<FileInfo> RetrieveAllReceipts()
|
||||
{
|
||||
var targetDirectory = GetReceiptDirectoryPath();
|
||||
var directory = new DirectoryInfo(targetDirectory);
|
||||
|
||||
return directory.GetFiles().ToList();
|
||||
}
|
||||
|
||||
public async Task<string> ReadReceiptFile(string? fileName)
|
||||
{
|
||||
if (fileName == null)
|
||||
return "";
|
||||
|
||||
var targetDirectory = GetReceiptDirectoryPath();
|
||||
var filePath = Path.Combine(targetDirectory, fileName);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return "";
|
||||
|
||||
try
|
||||
{
|
||||
await using var stream = File.OpenRead(filePath);
|
||||
using var reader = new StreamReader(stream);
|
||||
return await reader.ReadToEndAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, e.Message);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OpenReceiptFile(string fileName)
|
||||
{
|
||||
var filePath = GetReceiptFilePath(fileName);
|
||||
|
||||
await Launcher.OpenAsync(new OpenFileRequest
|
||||
{
|
||||
File = new ReadOnlyFile(filePath)
|
||||
});
|
||||
}
|
||||
|
||||
public async Task WriteReceiptTextAsync(string fileName, string content)
|
||||
{
|
||||
var filePath = GetReceiptFilePath(fileName);
|
||||
|
||||
try
|
||||
{
|
||||
await using var stream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None);
|
||||
await using var writer = new StreamWriter(stream);
|
||||
await writer.WriteLineAsync(content);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, $"Errore durante la scrittura del file {fileName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using ConSegna.Shared.Core.Interfaces;
|
||||
|
||||
namespace ConSegna.Maui.Services;
|
||||
namespace ConSegna.Maui.Core.Services;
|
||||
|
||||
public class FormFactor : IFormFactor
|
||||
{
|
||||
@@ -2,7 +2,7 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SQLite;
|
||||
|
||||
namespace ConSegna.Maui.Services;
|
||||
namespace ConSegna.Maui.Core.Services;
|
||||
|
||||
public class LocalDbService
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using ConSegna.Shared.Core.Interfaces;
|
||||
|
||||
namespace ConSegna.Maui.Services;
|
||||
namespace ConSegna.Maui.Core.Services;
|
||||
|
||||
public class NetworkService : INetworkService
|
||||
{
|
||||
@@ -1,16 +1,22 @@
|
||||
using ConSegna.Shared.Core.Dto;
|
||||
using ConSegna.Maui.Core.Utility;
|
||||
using ConSegna.Shared.Core.Dto;
|
||||
using ConSegna.Shared.Core.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ConSegna.Maui.Services;
|
||||
namespace ConSegna.Maui.Core.Services;
|
||||
|
||||
public class SyncStorage(IIntegryApiService integryApiService, IDataStorage dataStorage, LocalDbService localDb, ILogger<SyncStorage> logger)
|
||||
: ISyncStorage
|
||||
public class SyncStorage(
|
||||
IIntegryApiService integryApiService,
|
||||
IDataStorage dataStorage,
|
||||
LocalDbService localDb,
|
||||
ILogger<SyncStorage> logger,
|
||||
IUtilityFile utilityFile
|
||||
) : ISyncStorage
|
||||
{
|
||||
public async Task<bool> GetAndSaveDatiClienti()
|
||||
{
|
||||
#if DEBUG
|
||||
var dataDoc = new DateTime(2025, 06, 04);
|
||||
var dataDoc = new DateTime(2025, 11, 14);
|
||||
//var dataDoc = DateTime.Today;
|
||||
#else
|
||||
var dataDoc = DateTime.Today;
|
||||
@@ -25,17 +31,16 @@ public class SyncStorage(IIntegryApiService integryApiService, IDataStorage data
|
||||
|
||||
foreach (var bolla in datiClienti.DatiConsegne)
|
||||
{
|
||||
bolla.FileName =
|
||||
$"{bolla.CodDtip}_{bolla.SerDoc.Replace("/", "-").Replace("\\", "-")}_{bolla.NumDoc:D6}_{dataDoc:yyMMdd}_{bolla.CodAnag}.pdf";
|
||||
bolla.FileName = utilityFile.ComposeFileName(
|
||||
bolla.CodDtip, bolla.DataDoc, bolla.SerDoc, bolla.NumDoc, bolla.CodAnag
|
||||
);
|
||||
|
||||
var filePath = dataStorage.GetFilePath(bolla.FileName, true);
|
||||
|
||||
if (filePath != null)
|
||||
{
|
||||
bolla.Firmato = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await localDb.SaveDatiCliente(dataToSave);
|
||||
}
|
||||
14
ConSegna.Maui/Core/System/GenericSystemService.cs
Normal file
14
ConSegna.Maui/Core/System/GenericSystemService.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using ConSegna.Shared.Core.Interfaces;
|
||||
|
||||
namespace ConSegna.Maui.Core.System;
|
||||
|
||||
public class GenericSystemService : IGenericSystemService
|
||||
{
|
||||
public string GetCurrentAppVersion() => AppInfo.VersionString;
|
||||
|
||||
public void OpenSettings() => AppInfo.Current.ShowSettingsUI();
|
||||
|
||||
public void CloseApp() => Application.Current?.Quit();
|
||||
|
||||
public DateTime DataApp { get; set; } = DateTime.Today;
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
using ConSegna.Shared.Core.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ConSegna.Maui.Services;
|
||||
namespace ConSegna.Maui.Core.System;
|
||||
|
||||
public class GeolocationService(ILogger<GeolocationService> logger) : IGeolocationService
|
||||
{
|
||||
public async Task<bool> RequestAccess()
|
||||
{
|
||||
var perm = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
|
||||
return perm == PermissionStatus.Granted;
|
||||
}
|
||||
|
||||
private async Task<Location?> GetLocationAsync()
|
||||
{
|
||||
try
|
||||
50
ConSegna.Maui/Core/Utility/UtilityFile.cs
Normal file
50
ConSegna.Maui/Core/Utility/UtilityFile.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using ConSegna.Shared.Core.Interfaces;
|
||||
using System.Globalization;
|
||||
|
||||
namespace ConSegna.Maui.Core.Utility;
|
||||
|
||||
public partial class UtilityFile : IUtilityFile
|
||||
{
|
||||
[GeneratedRegex(@".*_(\d{6})_.*")]
|
||||
private static partial Regex Date_yyMMdd();
|
||||
|
||||
[GeneratedRegex(@".*_(\d{8})_.*")]
|
||||
private static partial Regex Date_yyyyMMdd();
|
||||
|
||||
public string ComposeFileName(string codDtip, DateTime dataDoc, string serDoc, int numDoc, string codAnag)
|
||||
{
|
||||
var serDocReplaced = serDoc.Replace("/", "-").Replace("\\", "-");
|
||||
|
||||
return $"{codDtip}_{dataDoc:yyyyMMdd}_{codAnag}_{serDocReplaced}_{numDoc:D5}.pdf";
|
||||
}
|
||||
|
||||
public DateTime? DetectDataDocFromFileName(string fileName)
|
||||
{
|
||||
var match = Date_yyMMdd().Match(fileName);
|
||||
|
||||
if (match.Success &&
|
||||
DateTime.TryParseExact(
|
||||
match.Groups[1].Value,
|
||||
"yyMMdd",
|
||||
null,
|
||||
DateTimeStyles.None, out var date))
|
||||
{
|
||||
return date;
|
||||
}
|
||||
|
||||
match = Date_yyyyMMdd().Match(fileName);
|
||||
|
||||
if (match.Success &&
|
||||
DateTime.TryParseExact(
|
||||
match.Groups[1].Value,
|
||||
"yyyyMMdd",
|
||||
null,
|
||||
DateTimeStyles.None, out date))
|
||||
{
|
||||
return date;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
using CommunityToolkit.Maui;
|
||||
using ConSegna.Maui.Core.Logger;
|
||||
using ConSegna.Maui.Core.Services;
|
||||
using ConSegna.Maui.Core.System;
|
||||
using ConSegna.Maui.Core.Utility;
|
||||
using ConSegna.Shared;
|
||||
using ConSegna.Shared.Core.Helpers;
|
||||
using ConSegna.Shared.Core.Interfaces;
|
||||
@@ -6,7 +10,6 @@ using ConSegna.Shared.Core.Services;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ConSegna.Maui.Services;
|
||||
using ConSegna.Maui.Services.Logger;
|
||||
using ConSegna.Shared.Core.Messages;
|
||||
using IntegryApiClient.MAUI;
|
||||
using Maui.Android.InAppUpdates;
|
||||
@@ -81,6 +84,10 @@ namespace ConSegna.Maui
|
||||
builder.Services.AddSingleton<IFormFactor, FormFactor>();
|
||||
builder.Services.AddSingleton<IDeviceOrientationService, DeviceOrientationService>();
|
||||
builder.Services.AddSingleton<IGeolocationService, GeolocationService>();
|
||||
builder.Services.AddSingleton<IGenericSystemService, GenericSystemService>();
|
||||
builder.Services.AddSingleton<IUtilityFile, UtilityFile>();
|
||||
builder.Services.AddSingleton<IUtilityFile, UtilityFile>();
|
||||
builder.Services.AddSingleton<ILogReceiptsService, LogReceiptsService>();
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@using System.Text.Json
|
||||
@inject IJSRuntime JS
|
||||
@inject IJSRuntime Js
|
||||
|
||||
<div class="header">
|
||||
<div class="header-content px-5">
|
||||
<div class="header-content">
|
||||
<div class="side">
|
||||
@if (!HideBack)
|
||||
{
|
||||
@@ -13,6 +13,10 @@
|
||||
</div>
|
||||
<div class="center">
|
||||
<h5>@Title</h5>
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
</div>
|
||||
<div class="side">
|
||||
@if (!HideSearch)
|
||||
@@ -32,7 +36,7 @@
|
||||
<div class="modalSearch-searchBox">
|
||||
<i class="px-2 ri-search-2-line"></i>
|
||||
<InputText class="form-control" @bind-Value="SearchText" @bind-Value:after="Search"/>
|
||||
<i @onclick="() => RapidSearch(null)" class="@(SearchText.IsNullOrEmpty() ? _closeButton : _closeButtonActive) px-2 ri-close-circle-fill"></i>
|
||||
<i @onclick="() => RapidSearch(null)" class="@(SearchText.IsNullOrEmpty() ? CloseButton : CloseButtonActive) px-2 ri-close-circle-fill"></i>
|
||||
</div>
|
||||
<span @onclick="CloseModal" class="modalSearch-close-button ps-3">Annulla</span>
|
||||
</div>
|
||||
@@ -64,20 +68,22 @@
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter] public string Title { get; set; }
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
[Parameter] public string Title { get; set; } = "";
|
||||
|
||||
[Parameter] public bool HideSearch { get; set; }
|
||||
[Parameter] public EventCallback<string> OnSearch { get; set; }
|
||||
|
||||
[Parameter] public bool HideBack { get; set; } = true;
|
||||
|
||||
private Modal modal = default!;
|
||||
private Modal modal = null!;
|
||||
|
||||
//Filter search
|
||||
private string? SearchText { get; set; }
|
||||
private List<string>? LatestResearch { get; set; } = [];
|
||||
private string _closeButton = "close-button";
|
||||
private string _closeButtonActive = "close-button active";
|
||||
private const string CloseButton = "close-button";
|
||||
private const string CloseButtonActive = "close-button active";
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
@@ -117,7 +123,6 @@
|
||||
LatestResearch.Insert(0, SearchText!);
|
||||
}
|
||||
|
||||
//Limita la grandezza della lista a 10 elementi
|
||||
while (LatestResearch.Count > 10)
|
||||
{
|
||||
LatestResearch.RemoveAt(LatestResearch.Count - 1);
|
||||
@@ -139,6 +144,6 @@
|
||||
|
||||
private async Task Back()
|
||||
{
|
||||
await JS.InvokeVoidAsync("goBack");
|
||||
await Js.InvokeVoidAsync("goBack");
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
.header {
|
||||
background-color: var(--primary-color);
|
||||
border-radius: 0 0 50px 50px;
|
||||
border-radius: 2em;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
top: .5rem;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
width: calc(100% - 2rem);
|
||||
z-index: 1000;
|
||||
margin-left: 1rem;
|
||||
box-shadow: 15px 15px 20px 0px #00000017;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
@@ -13,20 +15,25 @@
|
||||
justify-content: space-between;
|
||||
color: var(--lighter-color);
|
||||
align-items: center;
|
||||
padding-top: .5rem;
|
||||
padding: .25rem 1rem;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.header-content > .side {
|
||||
display: block;
|
||||
min-width: 20px;
|
||||
min-height: 30px;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header-content > .center > h5 {
|
||||
color: var(--lighter-color);
|
||||
text-align: center;
|
||||
font-weight: 800;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.header-content > .side ::deep > button {
|
||||
@@ -35,9 +42,13 @@
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.header-content > .side ::deep > button:focus { box-shadow: none !important; }
|
||||
.header-content > .side ::deep > button:focus {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.sub-content { color: var(--lighter-color); }
|
||||
.sub-content {
|
||||
color: var(--lighter-color);
|
||||
}
|
||||
|
||||
.latest {
|
||||
display: flex;
|
||||
@@ -50,7 +61,9 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.latest > .body { cursor: pointer; }
|
||||
.latest > .body {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.latest > .body > div > i {
|
||||
font-size: large;
|
||||
@@ -65,12 +78,16 @@
|
||||
.line-separator {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: 1px solid hsl(from var(--disable-color) h s 90%);
|
||||
border: .05rem solid hsl(from var(--disable-color) h s 90%);
|
||||
}
|
||||
|
||||
.close-button { display: none; }
|
||||
.close-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.close-button.active { display: block; }
|
||||
.close-button.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@supports (-webkit-touch-callout: none) {
|
||||
.header {
|
||||
|
||||
@@ -8,6 +8,12 @@ main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.container{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
.navbar {
|
||||
background-color: var(--lighter-color);
|
||||
border-radius: 50px 50px 0 0;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
bottom: .5rem;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.container-fluid{
|
||||
margin: 0 1rem;
|
||||
padding: 0;
|
||||
background: white;
|
||||
border-radius: 3em;
|
||||
box-shadow: 15px 15px 20px 0px #00000017;
|
||||
}
|
||||
|
||||
.navbar-expand { padding: 0 !important; }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@attribute [Authorize]
|
||||
@using ConSegna.Shared.Core.Interfaces
|
||||
@using ConSegna.Shared.Components.Layout
|
||||
@using ConSegna.Shared.Components.SingleElements
|
||||
@using ConSegna.Shared.Components.SingleElements.Input
|
||||
@inject DetailConsegnaDto DetailConsegnaDto
|
||||
@inject ModalRef ModalRef
|
||||
@inject IFormFactor FormFactor
|
||||
@@ -10,13 +10,15 @@
|
||||
@inject IDataStorage DataStorage
|
||||
@inject IEditFileServices EditFileServices
|
||||
@inject SignaturePageData SignaturePageData
|
||||
@inject ILogReceiptsService LogReceiptsService
|
||||
|
||||
<HeaderLayout HideBack="false" HideSearch="true" Title="Dettagli"/>
|
||||
|
||||
<div class="content">
|
||||
<div class="my-2 top-detail">
|
||||
<span class="cliente">@DetailConsegnaDto.DatiConsegne[0].Cliente</span>
|
||||
<span class="indirizzo">@DetailConsegnaDto.DatiConsegne[0].Indirizzo - @DetailConsegnaDto.DatiConsegne[0].Citta</span>
|
||||
<span
|
||||
class="indirizzo">@DetailConsegnaDto.DatiConsegne[0].Indirizzo - @DetailConsegnaDto.DatiConsegne[0].Citta</span>
|
||||
</div>
|
||||
|
||||
<div class="row card-container mb-3">
|
||||
@@ -30,7 +32,7 @@
|
||||
<span class="card-subtitle">Da incassare</span>
|
||||
</div>
|
||||
|
||||
<div @onclick="OpenMap" class="col card-body">
|
||||
<div @onclick="OpenMap" class="col card-body ripple-container">
|
||||
<span class="card-title icon">
|
||||
<i class="ri-navigation-line"></i>
|
||||
</span>
|
||||
@@ -62,12 +64,22 @@
|
||||
|
||||
<div class="carousel-sub-header">
|
||||
<span class="note-title">
|
||||
Note: <span class="note-text">@(doc.Note.IsNullOrEmpty() ? "Nessuna nota presente" : doc.Note)</span>
|
||||
Note: <span
|
||||
class="note-text">@(doc.Note.IsNullOrEmpty() ? "Nessuna nota presente" : doc.Note)</span>
|
||||
</span>
|
||||
<div @onclick="() => NuovaNota(doc)" class="button-container">
|
||||
<div class="card-button note">
|
||||
|
||||
<div class="button-container">
|
||||
<div @onclick="() => NuovaNota(doc)" class="card-button ripple-container note">
|
||||
<span>Aggiungi note</span>
|
||||
</div>
|
||||
|
||||
@if (DetailConsegnaDto.DatiConsegne[0].ImpIncasso > 0)
|
||||
{
|
||||
<div @onclick="() => RicalcolaImporto(doc)" class="card-button ripple-container note">
|
||||
<i class="ri-calculator-line"></i>
|
||||
<span>Ricalcola importo</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -85,11 +97,11 @@
|
||||
</div>
|
||||
|
||||
<div class="button-container">
|
||||
<div @onclick="() => OpenPdf(doc)" class="card-button">
|
||||
<div @onclick="() => OpenPdf(doc)" class="card-button ripple-container">
|
||||
<span>Visualizza</span>
|
||||
</div>
|
||||
|
||||
<div @onclick="() => OnClickFirma(doc)" class="card-button firma">
|
||||
<div @onclick="() => OnClickFirma(doc)" class="card-button ripple-white firma ripple-container">
|
||||
<i class="ri-edit-line"></i>
|
||||
<span>Firma</span>
|
||||
</div>
|
||||
@@ -109,6 +121,8 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (SystemService.DataApp == DateTime.Today)
|
||||
{
|
||||
<div class="card-body">
|
||||
<div class="carousel-header mb-2">
|
||||
<div class="carousel-title">Registra incasso</div>
|
||||
@@ -118,13 +132,11 @@
|
||||
<div class="row d-flex align-items-center" style="width: 100%">
|
||||
<div class="col modalSearch-searchBox">
|
||||
<i class="px-2 ri-wallet-line"></i>
|
||||
<CurrencyInput
|
||||
TValue="decimal"
|
||||
Locale="fr-FR"
|
||||
@bind-Value="@Incasso"
|
||||
<IyCurrencyInput @bind-Value="@Incasso"
|
||||
@bind-Value:after="CalcTotIncasso"
|
||||
class="form-control"/>
|
||||
<i @onclick="ClearIncasso" class="@(Incasso == 0 ? _closeButton : _closeButtonActive) px-2 ri-close-circle-fill"></i>
|
||||
Class="form-control"/>
|
||||
<i @onclick="ClearIncasso"
|
||||
class="@(Incasso == 0 ? _closeButton : _closeButtonActive) px-2 ri-close-circle-fill"></i>
|
||||
</div>
|
||||
<span @onclick="AutoIncasso" class="col-auto modalSearch-close-button pe-0">Seleziona tutto</span>
|
||||
</div>
|
||||
@@ -138,7 +150,8 @@
|
||||
<div class="sospeso">
|
||||
<div class="checkbox-wrapper">
|
||||
<div>
|
||||
<InputCheckbox AdditionalAttributes="@(Incasso <= 0 ? new Dictionary<string, object> { { "disabled", "disabled" } } : new Dictionary<string, object>())"
|
||||
<InputCheckbox
|
||||
AdditionalAttributes="@(Incasso <= 0 ? new Dictionary<string, object> { { "disabled", "disabled" } } : new Dictionary<string, object>())"
|
||||
Value="sospeso.IsSelected"
|
||||
ValueChanged="@(value => OnSospesoChanged(value, sospeso))"
|
||||
ValueExpression="(() => sospeso.IsSelected)"/>
|
||||
@@ -161,21 +174,24 @@
|
||||
}
|
||||
|
||||
<div class="row card-container mb-3">
|
||||
<div @onclick="@(() => SelectTipoIncasso("Contanti"))" class="col card-body bordered @Contanti">
|
||||
<div @onclick="@(() => SelectTipoIncasso("Contanti"))"
|
||||
class="ripple-container col card-body bordered @Contanti">
|
||||
<span class="card-title icon">
|
||||
<i class="ri-coin-line"></i>
|
||||
</span>
|
||||
<span class="card-subtitle">Contanti</span>
|
||||
</div>
|
||||
|
||||
<div @onclick="@(() => SelectTipoIncasso("Assegni"))" class="col card-body bordered @Assegni">
|
||||
<div @onclick="@(() => SelectTipoIncasso("Assegni"))"
|
||||
class="ripple-container col card-body bordered @Assegni">
|
||||
<span class="card-title icon">
|
||||
<i class="ri-refund-line"></i>
|
||||
</span>
|
||||
<span class="card-subtitle">Assegni</span>
|
||||
</div>
|
||||
|
||||
<div @onclick="@(() => SelectTipoIncasso("Carte"))" class="col card-body bordered @Carte">
|
||||
<div @onclick="@(() => SelectTipoIncasso("Carte"))"
|
||||
class="ripple-container col card-body bordered @Carte">
|
||||
<span class="card-title icon">
|
||||
<i class="ri-bank-card-line"></i>
|
||||
</span>
|
||||
@@ -235,13 +251,15 @@
|
||||
</div>
|
||||
|
||||
<div class="button-container justify-content-center">
|
||||
<div @onclick="OnClickSaveSospesi" class="card-button firma">
|
||||
<div @onclick="OnClickSaveSospesi" class="card-button firma ripple-container">
|
||||
<span>Registra</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<RicalcolaImportoModal DettaglioRighe="DettaglioRighe"/>
|
||||
<ConfirmModal ConfirmText="@ConfirmModalText" ConfirmClick="@ConfirmModalClick"/>
|
||||
<InputModal MaxLength="350" Title="Aggiungi nota" InputText="@Nota" ReturnText="OnReturnInputNote"/>
|
||||
<SpinnerModal/>
|
||||
@@ -272,6 +290,7 @@
|
||||
private string _closeButtonActive = "close-button active";
|
||||
|
||||
private List<SospesiClienteDTO> DocumentiPagati { get; set; } = [];
|
||||
private List<DettaglioRigheDTO> DettaglioRighe { get; set; } = [];
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -420,6 +439,14 @@
|
||||
await ModalRef.InputModal.ShowAsync();
|
||||
}
|
||||
|
||||
private async Task RicalcolaImporto(DatiConsegneDTO doc)
|
||||
{
|
||||
DettaglioRighe = doc.DettaglioRighe;
|
||||
StateHasChanged();
|
||||
|
||||
await ModalRef.RicalcolaImporto.ShowAsync();
|
||||
}
|
||||
|
||||
private async Task OnReturnInputNote(string nota)
|
||||
{
|
||||
await ModalRef.SpinnerModal.ShowAsync();
|
||||
@@ -591,6 +618,15 @@
|
||||
private async Task SaveSospesi()
|
||||
{
|
||||
await ModalRef.SpinnerModal.ShowAsync();
|
||||
|
||||
string paymentMethod;
|
||||
if (Contanti) paymentMethod = "Contanti";
|
||||
else if (Assegni) paymentMethod = "Assegni";
|
||||
else if (Carte) paymentMethod = "Carta";
|
||||
else paymentMethod = "Non dichiarato";
|
||||
|
||||
await LogReceiptsService.AddReceipt(DocumentiPagati, Incasso, DaPagare, paymentMethod);
|
||||
|
||||
var dataPagamento = DateTime.Now;
|
||||
|
||||
if (DetailConsegnaDto.Sospesi == null) return;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
.card-body {
|
||||
background-color: var(--lighter-color);
|
||||
border-radius: 15px;
|
||||
border-radius: 1.5em;
|
||||
padding: .5rem 1.1rem;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,6 @@
|
||||
|
||||
.card-button.note {
|
||||
padding: .1rem;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.card-button.firma {
|
||||
|
||||
@@ -4,23 +4,86 @@
|
||||
@using ConSegna.Shared.Components.Layout.Spinner
|
||||
@inject IFormFactor FormFactor
|
||||
@inject INetworkService NetworkService
|
||||
|
||||
@inject IGeolocationService GeolocationService
|
||||
@inject ModalRef ModalRef
|
||||
@inject NavigationManager NavigationManager
|
||||
@implements IDisposable
|
||||
|
||||
<SpinnerLayout/>
|
||||
|
||||
@code
|
||||
{
|
||||
<PermissionModal Title="Posizione obbligatoria!"
|
||||
Message="@PositionException"
|
||||
ActionButtonText="Impostazioni"
|
||||
ActionButton="() => SystemService.OpenSettings()"/>
|
||||
|
||||
@code {
|
||||
private const string PositionException = "L'accesso alla posizione <b>è obbligatoria</b> per le funzionalità del app; abilitala nell'app <b>Impostazioni</b> per continuare.";
|
||||
|
||||
private CancellationTokenSource? _cts;
|
||||
|
||||
private bool _isModalOpen;
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
var lastSyncDate = DateOnly.FromDateTime(LocalStorage.Get<DateTime>("last-sync"));
|
||||
var syncAntherDay = LocalStorage.Get<bool>("sync-another-day");
|
||||
|
||||
if (!FormFactor.IsWeb() && NetworkService.IsNetworkAvailable() && lastSyncDate < DateOnly.FromDateTime(DateTime.Now))
|
||||
if (syncAntherDay || FormFactor.IsWeb() || !NetworkService.IsNetworkAvailable() || lastSyncDate >= DateOnly.FromDateTime(DateTime.Now))
|
||||
return Task.CompletedTask;
|
||||
|
||||
var returnPath = System.Web.HttpUtility.UrlEncode("/");
|
||||
NavigationManager.NavigateTo($"/sync?path={returnPath}");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
NavigationManager.NavigateTo("/sync");
|
||||
return base.OnInitializedAsync();
|
||||
if (firstRender)
|
||||
{
|
||||
_cts = new CancellationTokenSource();
|
||||
_ = PermissionLoop(_cts.Token);
|
||||
}
|
||||
}
|
||||
|
||||
NavigationManager.NavigateTo("/Consegne");
|
||||
return base.OnInitializedAsync();
|
||||
private async Task PermissionLoop(CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
var hasPermission = await GeolocationService.RequestAccess();
|
||||
|
||||
if (hasPermission)
|
||||
{
|
||||
if (_isModalOpen)
|
||||
{
|
||||
await ModalRef.PermissionModal.HideAsync();
|
||||
_isModalOpen = false;
|
||||
}
|
||||
|
||||
NavigationManager.NavigateTo("/Consegne", replace: true);
|
||||
await _cts?.CancelAsync()!;
|
||||
return;
|
||||
}
|
||||
if (!_isModalOpen)
|
||||
{
|
||||
await ModalRef.PermissionModal.ShowAsync();
|
||||
_isModalOpen = true;
|
||||
}
|
||||
|
||||
await Task.Delay(2000, token);
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// Il task è stato cancellato
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts?.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
@page "/settings"
|
||||
@attribute [Authorize]
|
||||
@using ConSegna.Shared.Core.Helpers
|
||||
@using ConSegna.Shared.Core.Interfaces
|
||||
@using ConSegna.Shared.Components.Layout
|
||||
@using ConSegna.Shared.Components.SingleElements
|
||||
@inject IDataStorage DataStorage
|
||||
@inject ModalRef ModalRef
|
||||
|
||||
@@ -20,7 +17,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div @onclick="() => ViewLog()" class="card-body my-3">
|
||||
<div @onclick="ViewLog" class="card-body ripple-container my-3">
|
||||
<div class="titleCard">
|
||||
<div class="textTitle">
|
||||
<i class="ri-bug-line"></i>
|
||||
@@ -39,6 +36,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div @onclick="OpenListReceipts" class="card-body ripple-container my-3">
|
||||
<div class="button">
|
||||
<div>
|
||||
<i class="ri-receipt-line"></i>
|
||||
<span>Log incassi</span>
|
||||
</div>
|
||||
<i class="ri-arrow-right-s-line"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body my-3">
|
||||
<div class="titleCard">
|
||||
<div class="textTitle">
|
||||
@@ -73,7 +80,7 @@
|
||||
@foreach (var doc in DocList!)
|
||||
{
|
||||
<div class="documentList">
|
||||
<div @onclick="() => OpenPdf(doc.Name, false)" class="document">
|
||||
<div @onclick="() => OpenPdf(doc.Name, false)" class="ripple-container document">
|
||||
<i class="ri-file-pdf-2-line"></i>
|
||||
<span>@doc.Name</span>
|
||||
</div>
|
||||
@@ -127,21 +134,23 @@
|
||||
</div>
|
||||
|
||||
<ViewLogModal Log="@LogText" />
|
||||
<SelectReceipt FileList="Receipts" SelectClick="ViewReceipts" />
|
||||
|
||||
@code {
|
||||
private List<FileInfo>? DocList { get; set; }
|
||||
private List<FileInfo>? SignedDocList { get; set; }
|
||||
private List<FileInfo>? Certificate { get; set; }
|
||||
private List<FileInfo> Receipts { get; set; } = [];
|
||||
private FileInfo? LogFile { get; set; }
|
||||
|
||||
private string LogText { get; set; } = "";
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
DocList = DataStorage.RetrieveAllFile(false, false);
|
||||
SignedDocList = DataStorage.RetrieveAllFile(true, false);
|
||||
DocList = DataStorage.RetrieveAllFile(false, false)?.OrderBy(x => x.LastWriteTime).ToList();
|
||||
SignedDocList = DataStorage.RetrieveAllFile(true, false)?.OrderBy(x => x.LastWriteTime).ToList();
|
||||
Certificate = DataStorage.RetrieveAllFile(false, true);
|
||||
|
||||
Receipts = DataStorage.RetrieveAllReceipts().OrderByDescending(x => x.LastWriteTime).ToList();
|
||||
LogFile = DataStorage.RetrieveLogFile();
|
||||
|
||||
return base.OnInitializedAsync();
|
||||
@@ -157,4 +166,13 @@
|
||||
await ModalRef.ViewLogModal.ShowAsync();
|
||||
}
|
||||
|
||||
private async Task ViewReceipts(string fileName)
|
||||
{
|
||||
await DataStorage.OpenReceiptFile(fileName);
|
||||
}
|
||||
|
||||
private async Task OpenListReceipts()
|
||||
{
|
||||
await ModalRef.SelectReceiptModal.ShowAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
.card-body {
|
||||
background-color: var(--lighter-color);
|
||||
border-radius: 15px;
|
||||
border-radius: 1.5em;
|
||||
padding: .5rem 1.1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
@page "/Incassi"
|
||||
@attribute [Authorize]
|
||||
@using ConSegna.Shared.Core.Interfaces
|
||||
@using ConSegna.Shared.Components.Layout
|
||||
@using ConSegna.Shared.Components.Layout.Spinner
|
||||
@using ConSegna.Shared.Components.SingleElements
|
||||
@inject IDataStorage DataStorage
|
||||
@inject IIntegryApiService IntegryApiService
|
||||
@inject ModalRef ModalRef
|
||||
|
||||
<HeaderLayout HideSearch="true" Title="Incassi"/>
|
||||
<HeaderLayout HideSearch="true" Title="Incassi">
|
||||
<div class="center">
|
||||
<h5 style="font-size: small">@($"Incassi del {SystemService.DataApp:d}")</h5>
|
||||
</div>
|
||||
</HeaderLayout>
|
||||
|
||||
@if (DatiClienti.IsNullOrEmpty())
|
||||
{
|
||||
@@ -17,23 +19,16 @@
|
||||
else
|
||||
{
|
||||
<div class="content">
|
||||
<div class="card-body mb-3">
|
||||
<div class="titleCard">
|
||||
<div class="textTitle">
|
||||
<span>Incassi del @($"{DateTime.Now:d}")</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body subTitle my-2">
|
||||
@if (SystemService.DataApp == DateTime.Today)
|
||||
{
|
||||
<div class="card-body my-2">
|
||||
<div class="subTitleCard">
|
||||
<div class="textTitle">
|
||||
<span>Incasso bolle della giornata</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row card-container mb-3">
|
||||
<div class="row card-container">
|
||||
<div class="col card-body">
|
||||
<div class="totalCashDay">
|
||||
<div class="titleTotal">
|
||||
@@ -70,16 +65,16 @@ else
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body subTitle my-2">
|
||||
<div class="card-body my-2">
|
||||
<div class="subTitleCard">
|
||||
<div class="textTitle">
|
||||
<span>Incasso generale</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row card-container mb-3">
|
||||
<div class="row card-container">
|
||||
<div class="col card-body">
|
||||
<div class="totalCashDay">
|
||||
<div class="titleTotal">
|
||||
@@ -92,6 +87,7 @@ else
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body my-3">
|
||||
<div class="titleCard">
|
||||
@@ -99,9 +95,8 @@ else
|
||||
<span>Dettaglio incasso</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row card-container mb-3">
|
||||
<div class="row card-container">
|
||||
<div class="col card-body">
|
||||
<span class="card-title icon">
|
||||
<i class="ri-coin-line"></i>
|
||||
@@ -130,6 +125,7 @@ else
|
||||
<span class="card-subtitle">@($"{TotGeneric:C}")</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="bodyCard">
|
||||
@@ -187,7 +183,7 @@ else
|
||||
{
|
||||
<div class="line-separator my-1"></div>
|
||||
|
||||
@foreach (var docSospeso in DocSospesi.Select((value, index) => new { value, index }))
|
||||
foreach (var docSospeso in DocSospesi.Select((value, index) => new { value, index }))
|
||||
{
|
||||
var paymentData = docSospeso.value.PaymentData;
|
||||
var paid = false;
|
||||
@@ -208,15 +204,18 @@ else
|
||||
|
||||
<div class="bodyCard">
|
||||
<div class="titleTotal">
|
||||
<span class="docInfo">@($"{docSospeso.value.CodDtip} del {docSospeso.value.DataDoc:d} n. {docSospeso.value.SerDoc}/{docSospeso.value.NumDoc}")</span>
|
||||
<span
|
||||
class="docInfo">@($"{docSospeso.value.CodDtip} del {docSospeso.value.DataDoc:d} n. {docSospeso.value.SerDoc}/{docSospeso.value.NumDoc}")</span>
|
||||
|
||||
|
||||
<div>
|
||||
<span class="@("detail-info-text " + (partialImp ? "ritardo" : ""))">@($"{docSospeso.value.TotDoc:C}")</span>
|
||||
<span
|
||||
class="@("detail-info-text " + (partialImp ? "ritardo" : ""))">@($"{docSospeso.value.TotDoc:C}")</span>
|
||||
|
||||
@if (partialImp)
|
||||
{
|
||||
<span class="detail-info-text">@($"{docSospeso.value.TotDoc - totalPaid:C}")</span>
|
||||
<span
|
||||
class="detail-info-text">@($"{docSospeso.value.TotDoc - totalPaid:C}")</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -229,8 +228,9 @@ else
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="card-body my-3">
|
||||
<div class="card-body ripple-container my-3">
|
||||
<div @onclick="SelectPrinter" class="button">
|
||||
<div>
|
||||
<i class="ri-printer-line"></i>
|
||||
@@ -289,6 +289,7 @@ else
|
||||
|
||||
TotIncassato = sospesiClienteList.Sum(x => x.ImportoPagato > x.ImpSospeso ? x.ImpSospeso : x.ImportoPagato);
|
||||
TotSospeso = TotAtteso - TotIncassato;
|
||||
TotSospeso = TotAtteso < 0 ? 0 : TotAtteso;
|
||||
|
||||
if (allPaymentData is not null)
|
||||
{
|
||||
@@ -340,12 +341,7 @@ else
|
||||
private async Task PrintReport(string printer)
|
||||
{
|
||||
await ModalRef.SpinnerModal.ShowAsync();
|
||||
#if DEBUG
|
||||
var dataDoc = new DateTime(2025, 06, 04);
|
||||
//var dataDoc = DateTime.Today;
|
||||
#else
|
||||
var dataDoc = DateTime.Today;
|
||||
#endif
|
||||
var dataDoc = SystemService.DataApp;
|
||||
|
||||
var jasperDto = new JasperDTO
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.card-body {
|
||||
background-color: var(--lighter-color);
|
||||
border-radius: 15px;
|
||||
border-radius: 1.5em;
|
||||
padding: .5rem 1.1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
}
|
||||
|
||||
.card-container > .card-body {
|
||||
min-height: 5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -136,3 +135,23 @@
|
||||
line-height: normal;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 100%;
|
||||
color: var(--lighter-color);
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.center > h5 {
|
||||
margin-bottom: 0 !important;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.center > i {
|
||||
font-weight: 800;
|
||||
}
|
||||
@@ -1,27 +1,27 @@
|
||||
@page "/Consegne"
|
||||
@attribute [Authorize]
|
||||
@using ConSegna.Shared.Core.Interfaces
|
||||
@using ConSegna.Shared.Components.Layout.Spinner
|
||||
@using ConSegna.Shared.Components.Layout
|
||||
@using ConSegna.Shared.Components.SingleElements.Input
|
||||
@inject IDataStorage DataStorage
|
||||
@inject Consegne Consegne
|
||||
|
||||
<HeaderLayout HideSearch="true" Title="Consegne"/>
|
||||
<HeaderLayout HideSearch="true" Title="Consegne">
|
||||
@* <div class="center" @onclick="() => _datePicker?.ToggleDropdown()"> *@
|
||||
<div class="center">
|
||||
<h5 style="font-size: small">@($"Giro consegne del {SystemService.DataApp:d}")</h5>
|
||||
@* <DatePickerPopup @ref="_datePicker" *@
|
||||
@* SelectedDate="SystemService.DataApp" *@
|
||||
@* SelectedDateChanged="OnDateChangedWithValue" /> *@
|
||||
</div>
|
||||
</HeaderLayout>Vers
|
||||
|
||||
<div class="content">
|
||||
@if (!GroupedList.IsNullOrEmpty())
|
||||
{
|
||||
<div class="card-body mb-3">
|
||||
<div class="titleCard">
|
||||
<div class="textTitle">
|
||||
<span>Giro consegne del @($"{DateTime.Now:d}")</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@foreach (var dati in GroupedList!)
|
||||
foreach (var dati in GroupedList!)
|
||||
{
|
||||
<div class="card-body mb-2">
|
||||
<div class="card-body mb-3 ripple-container">
|
||||
<div class="city" @onclick="() => OpenPageConsegne(dati.Value)">
|
||||
<div class="right">
|
||||
<i class="ri-building-2-line"></i>
|
||||
@@ -49,6 +49,8 @@
|
||||
|
||||
private bool RetrieveFinished { get; set; }
|
||||
|
||||
private DatePickerPopup? _datePicker;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
RetrieveFinished = false;
|
||||
@@ -83,4 +85,11 @@
|
||||
NavigationManager.NavigateTo("/Consegne/List");
|
||||
}
|
||||
|
||||
private Task OnDateChangedWithValue(DateTime? newDate)
|
||||
{
|
||||
SystemService.DataApp = newDate!.Value;
|
||||
NavigationManager.NavigateTo("sync");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
.card-body {
|
||||
background-color: var(--lighter-color);
|
||||
border-radius: 15px;
|
||||
border-radius: 1.5em;
|
||||
padding: .5rem 1.1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -19,7 +19,9 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.city > i { color: var(--disable-color); }
|
||||
.city > i {
|
||||
color: var(--disable-color);
|
||||
}
|
||||
|
||||
.city i {
|
||||
font-size: 1.5rem;
|
||||
@@ -31,3 +33,23 @@
|
||||
font-size: medium;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 100%;
|
||||
color: var(--lighter-color);
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.center > h5 {
|
||||
margin-bottom: 0 !important;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.center > i {
|
||||
font-weight: 800;
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
@page "/sync"
|
||||
@using ConSegna.Shared.Core.Interfaces
|
||||
@using ConSegna.Shared.Components.Layout.Spinner
|
||||
@using Microsoft.Extensions.Logging
|
||||
@attribute [Authorize]
|
||||
@@ -7,11 +6,18 @@
|
||||
@inject IDataStorage DataStorage
|
||||
@inject IIntegryApiService IntegryApiService
|
||||
@inject ILogger<SyncPage> Logger
|
||||
@inject IUtilityFile UtilityFile
|
||||
|
||||
<SyncSpinner Text="@SyncText"/>
|
||||
|
||||
<AppVersion/>
|
||||
|
||||
<NavigationLock ConfirmExternalNavigation="true"
|
||||
OnBeforeInternalNavigation="PreventNavigation" />
|
||||
|
||||
@code {
|
||||
private string SyncText { get; set; }
|
||||
private string SyncText { get; set; } = "";
|
||||
private bool _allowNavigation;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -99,18 +105,20 @@
|
||||
StateHasChanged();
|
||||
|
||||
LocalStorage.Set("last-sync", DateTime.Now);
|
||||
LocalStorage.Set("sync-another-day", SystemService.DataApp != DateTime.Today);
|
||||
|
||||
NavigationManager.NavigateTo("/Consegne");
|
||||
var pathQuery = System.Web.HttpUtility.ParseQueryString(new UriBuilder(NavigationManager.Uri).Query);
|
||||
var originalPath = pathQuery["path"] ?? null;
|
||||
var path = originalPath ?? "/Consegne";
|
||||
|
||||
_allowNavigation = true;
|
||||
NavigationManager.NavigateTo(path, replace: true);
|
||||
}
|
||||
|
||||
private static List<(JasperDTO, string)> CreateJasperDtoList(List<DatiClientiDTO> retrieveDatiClienti)
|
||||
private List<(JasperDTO, string)> CreateJasperDtoList(List<DatiClientiDTO> retrieveDatiClienti)
|
||||
{
|
||||
#if DEBUG
|
||||
var dataDoc = new DateTime(2025, 06, 04);
|
||||
//var dataDoc = DateTime.Today;
|
||||
#else
|
||||
var dataDoc = DateTime.Today;
|
||||
#endif
|
||||
var dataDoc = SystemService.DataApp;
|
||||
|
||||
List<(JasperDTO, string)> returnData = [];
|
||||
|
||||
foreach (var bolla in retrieveDatiClienti.SelectMany(datiClienti => datiClienti.DatiConsegne))
|
||||
@@ -154,11 +162,20 @@
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
returnData.Add((jasperDto, $"{bolla.CodDtip}_{bolla.SerDoc.Replace("/", "-").Replace("\\", "-")}_{bolla.NumDoc:D6}_{dataDoc:yyMMdd}_{bolla.CodAnag}.pdf"));
|
||||
returnData.Add((
|
||||
jasperDto,
|
||||
UtilityFile.ComposeFileName(bolla.CodDtip, bolla.DataDoc, bolla.SerDoc, bolla.NumDoc, bolla.CodAnag)
|
||||
));
|
||||
}
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
private void PreventNavigation(LocationChangingContext context)
|
||||
{
|
||||
if (_allowNavigation)
|
||||
return;
|
||||
|
||||
context.PreventNavigation();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
@page "/Utente"
|
||||
@attribute [Authorize]
|
||||
@using ConSegna.Shared.Core.Interfaces
|
||||
@using ConSegna.Shared.Core.Services
|
||||
@using Microsoft.Extensions.Logging
|
||||
@using ConSegna.Shared.Components.Layout
|
||||
@inject AppAuthenticationStateProvider AuthenticationStateProvider
|
||||
@@ -14,13 +13,14 @@
|
||||
<div class="content">
|
||||
<div class="card-body">
|
||||
<div class="userInfoContainer">
|
||||
<div class="userIcon">
|
||||
<i class="ri-user-line"></i>
|
||||
</div>
|
||||
|
||||
<div class="userInfo">
|
||||
<span class="username">@Fullname</span>
|
||||
|
||||
<div class="line-separator my-1"></div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="date-container">
|
||||
<span>Stato connessione</span>
|
||||
@if (NetworkService.IsNetworkAvailable())
|
||||
{
|
||||
<div class="status online">
|
||||
@@ -36,22 +36,17 @@
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body mt-3">
|
||||
<div class="button">
|
||||
<div>
|
||||
<i class="ri-time-line"></i>
|
||||
<div class="date-container">
|
||||
<span>Ultima sincronizzazione</span>
|
||||
<span class="date">@LastSync.ToString("g")</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="line-separator my-1"></div>
|
||||
|
||||
<div class="card-body ripple-container mt-3">
|
||||
<div @onclick="Sync" class="button @(Unavailable ? "unavailable" : "")">
|
||||
<div>
|
||||
<i class="ri-loop-left-line"></i>
|
||||
@@ -61,7 +56,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body mt-3">
|
||||
<div class="card-body ripple-container mt-3">
|
||||
<div @onclick="OpenSettings" class="button">
|
||||
<div>
|
||||
<i class="ri-code-s-slash-line"></i>
|
||||
@@ -71,7 +66,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body mt-3">
|
||||
<div class="card-body ripple-container mt-3">
|
||||
<div @onclick="SignOut" class="button">
|
||||
<div>
|
||||
<i class="ri-logout-box-line"></i>
|
||||
@@ -80,6 +75,8 @@
|
||||
<i class="ri-arrow-right-s-line"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AppVersion/>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
@@ -130,4 +127,5 @@
|
||||
{
|
||||
NavigationManager.NavigateTo("settings");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
.card-body {
|
||||
background-color: var(--lighter-color);
|
||||
border-radius: 15px;
|
||||
border-radius: 1.5em;
|
||||
padding: .5rem 1.1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -23,18 +23,27 @@
|
||||
color: var(--dark-gray);
|
||||
}
|
||||
|
||||
.userInfo { line-height: normal; }
|
||||
.userInfo {
|
||||
line-height: normal;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-size: large;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.status { font-weight: 700; }
|
||||
.status {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.status.online { color: var(--lighter-green); }
|
||||
.status.online {
|
||||
color: var(--lighter-green);
|
||||
}
|
||||
|
||||
.status.offline { color: var(--red); }
|
||||
.status.offline {
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
.button {
|
||||
font-size: 1.1rem;
|
||||
@@ -50,9 +59,13 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.button > i { color: var(--disable-color); }
|
||||
.button > i {
|
||||
color: var(--disable-color);
|
||||
}
|
||||
|
||||
.button.unavailable { color: var(--disable-color) !important; }
|
||||
.button.unavailable {
|
||||
color: var(--disable-color) !important;
|
||||
}
|
||||
|
||||
.button i {
|
||||
font-size: 1.5rem;
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
@using Microsoft.Extensions.Logging
|
||||
@using ConSegna.Shared.Components.SingleElements
|
||||
@inject ILogger<Routes> Logger
|
||||
|
||||
<ErrorBoundary @ref="ErrorBoundary">
|
||||
<ChildContent>
|
||||
<CascadingAuthenticationState>
|
||||
@@ -36,13 +32,11 @@
|
||||
|
||||
<ErrorContent>
|
||||
<ExceptionModal @ref="ExceptionModal"
|
||||
Exception="@context"
|
||||
ErrorBoundary="@ErrorBoundary"
|
||||
OnRetry="() => ErrorBoundary?.Recover()"/>
|
||||
Exception="@context"/>
|
||||
</ErrorContent>
|
||||
</ErrorBoundary>
|
||||
|
||||
@code {
|
||||
private ErrorBoundary? ErrorBoundary { get; set; }
|
||||
private ExceptionModal ExceptionModal { get; set; }
|
||||
private ExceptionModal? ExceptionModal { get; set; }
|
||||
}
|
||||
17
ConSegna.Shared/Components/SingleElements/AppVersion.razor
Normal file
17
ConSegna.Shared/Components/SingleElements/AppVersion.razor
Normal file
@@ -0,0 +1,17 @@
|
||||
<div class="app-version">
|
||||
<span>@AppVersionString</span>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
private string AppVersionString { get; set; } = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
#if DEBUG
|
||||
AppVersionString = $"v{SystemService.GetCurrentAppVersion()} [DEBUG]";
|
||||
#else
|
||||
AppVersionString = $"v{SystemService.GetCurrentAppVersion()}";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
.app-version{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.app-version span{
|
||||
font-size: smaller;
|
||||
color: #616161;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
@using System.Globalization
|
||||
|
||||
<div class="datepicker-wrapper">
|
||||
|
||||
<i class="bi bi-calendar-event"
|
||||
@onclick="ToggleDropdown"
|
||||
@onclick:stopPropagation>
|
||||
</i>
|
||||
|
||||
@if (_isOpen)
|
||||
{
|
||||
<div class="datepicker-backdrop"
|
||||
@onclick="CloseDropdown"
|
||||
@onclick:stopPropagation>
|
||||
</div>
|
||||
|
||||
<div class="datepicker-dialog card shadow-lg"
|
||||
@onclick:stopPropagation>
|
||||
|
||||
<div class="card-header bg-white border-bottom-0 d-flex justify-content-between align-items-center">
|
||||
<i @onclick="PrevMonth"
|
||||
@onclick:stopPropagation
|
||||
class="ri-arrow-left-wide-line ripple-container"></i>
|
||||
|
||||
<span class="fw-bold text-capitalize">
|
||||
@_currentMonth.ToString("MMMM yyyy", CultureInfo.CreateSpecificCulture("it-IT"))
|
||||
</span>
|
||||
|
||||
<i @onclick="NextMonth"
|
||||
@onclick:stopPropagation
|
||||
class="ri-arrow-right-wide-line ripple-container"></i>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-2">
|
||||
<div class="calendar-grid">
|
||||
|
||||
@foreach (var dayName in _dayNames)
|
||||
{
|
||||
<div class="text-center text-muted small fw-bold">@dayName</div>
|
||||
}
|
||||
|
||||
@for (var i = 0; i < OffsetDays; i++)
|
||||
{
|
||||
<div></div>
|
||||
}
|
||||
|
||||
@for (var day = 1; day <= DaysInMonth; day++)
|
||||
{
|
||||
var date = new DateTime(_currentMonth.Year, _currentMonth.Month, day);
|
||||
var isSelected = SelectedDate.HasValue && SelectedDate.Value.Date == date;
|
||||
var isToday = date == DateTime.Today;
|
||||
|
||||
if (date > DateTime.Today)
|
||||
{
|
||||
<div class="day-cell disabled">@day</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="day-cell @(isSelected ? "selected-day" : "") @(isToday ? "today-day" : "")"
|
||||
@onclick="() => SelectDate(date)"
|
||||
@onclick:stopPropagation>
|
||||
@day
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-footer bg-white border-top-0 text-end">
|
||||
<div class="card-button"
|
||||
@onclick="CloseDropdown"
|
||||
@onclick:stopPropagation>
|
||||
<span>Annulla</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public DateTime? SelectedDate { get; set; }
|
||||
[Parameter] public EventCallback<DateTime?> SelectedDateChanged { get; set; }
|
||||
|
||||
private bool _isOpen;
|
||||
private DateTime _currentMonth = DateTime.Today;
|
||||
private readonly string[] _dayNames = ["Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"];
|
||||
|
||||
private int DaysInMonth => DateTime.DaysInMonth(_currentMonth.Year, _currentMonth.Month);
|
||||
|
||||
private int OffsetDays
|
||||
{
|
||||
get
|
||||
{
|
||||
var firstDay = new DateTime(_currentMonth.Year, _currentMonth.Month, 1);
|
||||
var dayOfWeek = (int)firstDay.DayOfWeek;
|
||||
return (dayOfWeek == 0 ? 7 : dayOfWeek) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleDropdown()
|
||||
{
|
||||
_isOpen = !_isOpen;
|
||||
if (_isOpen && SelectedDate.HasValue)
|
||||
_currentMonth = SelectedDate.Value;
|
||||
}
|
||||
|
||||
private void CloseDropdown() => _isOpen = false;
|
||||
private void PrevMonth() => _currentMonth = _currentMonth.AddMonths(-1);
|
||||
private void NextMonth() => _currentMonth = _currentMonth.AddMonths(1);
|
||||
|
||||
private async Task SelectDate(DateTime date)
|
||||
{
|
||||
SelectedDate = date;
|
||||
await SelectedDateChanged.InvokeAsync(SelectedDate);
|
||||
_isOpen = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
.datepicker-wrapper {
|
||||
display: inline-block;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.card-header:first-child {
|
||||
border-radius: 1.5rem 1.5rem 0 0;
|
||||
}
|
||||
|
||||
.card-footer:last-child {
|
||||
border-radius: 0 0 1.5rem 1.5rem;
|
||||
}
|
||||
|
||||
.card-header > i {
|
||||
font-size: large;
|
||||
font-weight: 700;
|
||||
padding: .2rem;
|
||||
}
|
||||
|
||||
.datepicker-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
z-index: 1050;
|
||||
}
|
||||
|
||||
.datepicker-dialog {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1055;
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
animation: fadeIn 0.2s ease-out;
|
||||
}
|
||||
.calendar-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.day-cell {
|
||||
height: 38px;
|
||||
width: 38px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
margin: 0 auto;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.day-cell:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.selected-day {
|
||||
background-color: var(--primary-color) !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.today-day {
|
||||
border: 1px solid var(--primary-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card-button {
|
||||
background-color: transparent;
|
||||
padding: .5rem;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.disabled{
|
||||
color: gray;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -60%);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
@using System.Globalization
|
||||
|
||||
<input type="text"
|
||||
inputmode="decimal"
|
||||
class="@Class"
|
||||
value="@_displayValue"
|
||||
@onfocus="OnFocus"
|
||||
@onblur="OnBlur"
|
||||
@oninput="OnInput"
|
||||
placeholder="@Placeholder"/>
|
||||
|
||||
@code {
|
||||
[Parameter] public decimal Value { get; set; }
|
||||
[Parameter] public EventCallback<decimal> ValueChanged { get; set; }
|
||||
|
||||
[Parameter] public string Class { get; set; } = "form-control text-end";
|
||||
|
||||
[Parameter] public string Placeholder { get; set; } = "";
|
||||
|
||||
[Parameter] public string CurrencyFormat { get; set; } = "C2";
|
||||
|
||||
[Parameter] public CultureInfo Culture { get; set; } = CultureInfo.CurrentCulture;
|
||||
|
||||
private string? _displayValue;
|
||||
private bool _isFocused;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (!_isFocused)
|
||||
_displayValue = Value.ToString(CurrencyFormat, Culture);
|
||||
}
|
||||
|
||||
private void OnFocus()
|
||||
{
|
||||
_isFocused = true;
|
||||
_displayValue = Value == 0 ? "" : Value.ToString("0.##", Culture);
|
||||
}
|
||||
|
||||
private async Task OnBlur()
|
||||
{
|
||||
_isFocused = false;
|
||||
var inputClean = _displayValue;
|
||||
|
||||
if (decimal.TryParse(inputClean, NumberStyles.Any, Culture, out var result))
|
||||
Value = result;
|
||||
|
||||
await ValueChanged.InvokeAsync(Value);
|
||||
_displayValue = Value.ToString(CurrencyFormat, Culture);
|
||||
}
|
||||
|
||||
private void OnInput(ChangeEventArgs e)
|
||||
{
|
||||
_displayValue = e.Value?.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -63,14 +63,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
public async Task HideModalAsync()
|
||||
{
|
||||
if (Modal != null)
|
||||
{
|
||||
await Modal.HideAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnRetryClick()
|
||||
{
|
||||
await OnRetry.InvokeAsync();
|
||||
@@ -1,5 +1,4 @@
|
||||
@using ConSegna.Shared.Core.Helpers
|
||||
@inject ModalRef ModalRef
|
||||
@inject ModalRef ModalRef
|
||||
|
||||
<Modal @ref="ModalRef.InputModal" BodyCssClass="@("input-body-modal")" HeaderCssClass="@("hide-header")" IsVerticallyCentered="true">
|
||||
<BodyTemplate>
|
||||
@@ -0,0 +1,36 @@
|
||||
@inject ModalRef ModalRef
|
||||
|
||||
<Modal @ref="ModalRef.PermissionModal" HeaderCssClass="@("hide-header")" UseStaticBackdrop="true" IsVerticallyCentered="true">
|
||||
<BodyTemplate>
|
||||
<div class="exception-header mb-2">
|
||||
<i class="ri-emotion-unhappy-line"></i>
|
||||
<span>@Title</span>
|
||||
</div>
|
||||
<div class="text">
|
||||
<span>@((MarkupString)Message)</span>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<div @onclick="() => SystemService.CloseApp()" class="card-button">
|
||||
<span>Chiudi app</span>
|
||||
</div>
|
||||
|
||||
<div @onclick="OnActionButtonClick" class="card-button">
|
||||
<span>@ActionButtonText</span>
|
||||
</div>
|
||||
</div>
|
||||
</BodyTemplate>
|
||||
</Modal>
|
||||
|
||||
@code {
|
||||
[Parameter] public string Message { get; set; } = "";
|
||||
|
||||
[Parameter] public EventCallback ActionButton { get; set; }
|
||||
[Parameter] public string ActionButtonText { get; set; } = "Riprova";
|
||||
|
||||
[Parameter] public string Title { get; set; } = "Ops";
|
||||
|
||||
private async Task OnActionButtonClick()
|
||||
{
|
||||
await ActionButton.InvokeAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
.button-container {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
margin: 1.5rem 0 0 0;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: medium;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card-button {
|
||||
text-align: center;
|
||||
background-color: transparent;
|
||||
padding: .3rem 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.exception-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.exception-header > i {
|
||||
font-size: 3rem;
|
||||
line-height: normal;
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
.exception-header > span {
|
||||
font-size: x-large;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
code {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
color: var(--dark-gray);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
@inject ModalRef ModalRef
|
||||
|
||||
<Modal @ref="ModalRef.RicalcolaImporto" BodyCssClass="@("input-body-modal")" HeaderCssClass="@("hide-header")"
|
||||
IsVerticallyCentered="true">
|
||||
<BodyTemplate>
|
||||
<div class="header mt-2 mb-1">
|
||||
<span>Ricalcola importo</span>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
@foreach (var dettaglio in DettaglioRighe.Where(dettaglio => dettaglio.ImportoRiga > 0))
|
||||
{
|
||||
<div class="row">
|
||||
<span class="col descrizione">@dettaglio.Descrizione</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span class="col prezzo">
|
||||
@($"Prezzo netto: {@dettaglio.PrezzoUnit:C}")
|
||||
</span>
|
||||
|
||||
<div class="col-auto qta">
|
||||
<i @onclick="() => RemoveQta(dettaglio)" class="ri-subtract-line ripple-container"></i>
|
||||
<span class="pezzi">
|
||||
@dettaglio.QtaDoc.ToString("0") <span class="untMis">@dettaglio.UntMis</span>
|
||||
</span>
|
||||
<i @onclick="() => AddQta(dettaglio)" class="ri-add-large-line ripple-container"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="line-separator my-1"></div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="card-body mb-1 mt-3">
|
||||
<span class="tot-doc">@($"Totale netto: {TotDoc:C}")</span>
|
||||
</div>
|
||||
|
||||
<div class="button-container">
|
||||
<div @onclick="OnHideModalClick" class="card-button">
|
||||
<span>Chiudi</span>
|
||||
</div>
|
||||
</div>
|
||||
</BodyTemplate>
|
||||
</Modal>
|
||||
|
||||
@code {
|
||||
[Parameter] public List<DettaglioRigheDTO> DettaglioRighe { get; set; } = [];
|
||||
|
||||
private decimal TotDoc { get; set; } = new(0);
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
TotDoc = 0;
|
||||
|
||||
foreach (var row in DettaglioRighe)
|
||||
{
|
||||
row.TempQta = row.QtaDoc;
|
||||
|
||||
TotDoc += row.TempQta * row.PrezzoUnit;
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task OnHideModalClick()
|
||||
{
|
||||
await ModalRef.RicalcolaImporto.HideAsync();
|
||||
}
|
||||
|
||||
private void RemoveQta(DettaglioRigheDTO row)
|
||||
{
|
||||
if (row.TempQta == 0) return;
|
||||
|
||||
row.TempQta--;
|
||||
TotDoc -= row.PrezzoUnit;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void AddQta(DettaglioRigheDTO row)
|
||||
{
|
||||
if (row.TempQta == 0) return;
|
||||
|
||||
row.TempQta++;
|
||||
TotDoc += row.PrezzoUnit;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
.header {
|
||||
font-weight: 800;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
margin: .5rem 0;
|
||||
max-height: 50vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.bodyCard {
|
||||
line-height: normal;
|
||||
padding: .8rem 0;
|
||||
}
|
||||
|
||||
.titleCard {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.titleCard .docInfo { width: 50%; }
|
||||
|
||||
.titleCard > div {
|
||||
display: flex;
|
||||
gap: 2vw;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.titleCard > span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.card-button {
|
||||
text-align: center;
|
||||
background-color: transparent;
|
||||
padding: .3rem 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.card-body > .row { line-height: normal; }
|
||||
|
||||
.card-body > .row > * {
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.qta > .pezzi {
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.untMis { font-size: 1rem; }
|
||||
|
||||
.qta > i{
|
||||
padding: 1rem;
|
||||
font-weight: 700;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.tot-doc{
|
||||
font-weight: 700;
|
||||
font-size: larger;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
.card-body {
|
||||
background-color: var(--lighter-color);
|
||||
border-radius: 15px;
|
||||
border-radius: 1.5em;
|
||||
padding: .5rem 1.1rem;
|
||||
font-weight: 600;
|
||||
height: 50vh;
|
||||
@@ -0,0 +1,46 @@
|
||||
@inject ModalRef ModalRef
|
||||
|
||||
<Modal @ref="ModalRef.SelectReceiptModal" HeaderCssClass="@("hide-header")" IsVerticallyCentered="true">
|
||||
<BodyTemplate>
|
||||
<div class="header mb-2">
|
||||
<span>Seleziona il file</span>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
@foreach (var file in FileList)
|
||||
{
|
||||
<div @onclick="() => OnConfirmClick(file.Name)" class="bodyCard">
|
||||
<div class="titleCard">
|
||||
<span>@file.Name</span>
|
||||
<i class="ri-arrow-right-s-line"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="line-separator my-1"></div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="button-container">
|
||||
<div @onclick="HideModalAsync" class="card-button">
|
||||
<span>Chiudi</span>
|
||||
</div>
|
||||
</div>
|
||||
</BodyTemplate>
|
||||
</Modal>
|
||||
|
||||
@code {
|
||||
[Parameter] public EventCallback<string> SelectClick { get; set; }
|
||||
[Parameter] public List<FileInfo> FileList { get; set; } = [];
|
||||
|
||||
private async Task OnConfirmClick(string file)
|
||||
{
|
||||
await ModalRef.SelectReceiptModal.HideAsync();
|
||||
await SelectClick.InvokeAsync(file);
|
||||
}
|
||||
|
||||
private async Task HideModalAsync()
|
||||
{
|
||||
await ModalRef.SelectReceiptModal.HideAsync();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
.header {
|
||||
font-weight: 800;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
background-color: var(--lighter-color);
|
||||
border-radius: 1.5em;
|
||||
padding: .5rem 1.1rem;
|
||||
font-weight: 600;
|
||||
height: 50vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.bodyCard {
|
||||
line-height: normal;
|
||||
padding: .8rem 0;
|
||||
}
|
||||
|
||||
.titleCard {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.titleCard .docInfo { width: 50%; }
|
||||
|
||||
.titleCard > div {
|
||||
display: flex;
|
||||
gap: 2vw;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.titleCard > span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: end;
|
||||
margin: 1.5rem 0 0 0;
|
||||
}
|
||||
|
||||
.card-button {
|
||||
text-align: center;
|
||||
background-color: transparent;
|
||||
padding: .3rem 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
@using ConSegna.Shared.Components.Layout.Spinner
|
||||
@inject ModalRef ModalRef
|
||||
|
||||
<Modal UseStaticBackdrop="true" @ref="ModalRef.SpinnerModal" HeaderCssClass="@("hide-header")" IsVerticallyCentered="true">
|
||||
<Modal DialogCssClass="@(ModalRef.SpinnerModalSign ? "" : "remove-background")" UseStaticBackdrop="true" @ref="ModalRef.SpinnerModal" HeaderCssClass="@("hide-header")" IsVerticallyCentered="true">
|
||||
<BodyTemplate>
|
||||
@if (ModalRef.SpinnerModalSign)
|
||||
{
|
||||
@@ -0,0 +1,4 @@
|
||||
.remove-background > .modal-content{
|
||||
background: unset !important;
|
||||
border: unset !important;
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-3 py-2 rounded-4 border card-bg box-area">
|
||||
<div class="px-3 py-2 rounded-4 border card-bg box-area ripple-container">
|
||||
<div>
|
||||
<span>@Consegne[0].Indirizzo - @Consegne[0].Citta</span>
|
||||
</div>
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
.line-separator {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: 1px solid hsl(from var(--disable-color) h s 90%);
|
||||
border: .05rem solid hsl(from var(--disable-color) h s 90%);
|
||||
}
|
||||
|
||||
.sospeso {
|
||||
|
||||
@@ -33,5 +33,15 @@ public class DettaglioRigheDTO
|
||||
[JsonPropertyName("untMis")]
|
||||
public string UntMis { get; set; }
|
||||
|
||||
[JsonPropertyName("importoRiga")]
|
||||
public decimal ImportoRiga { get; set; }
|
||||
|
||||
[JsonIgnore] public decimal PrezzoUnit =>
|
||||
QtaDoc == 0 ? 0 : Math.Round(ImportoRiga / QtaDoc, 2, MidpointRounding.AwayFromZero);
|
||||
|
||||
[JsonIgnore] public bool CanBeUpdated => ImportoRiga > 0;
|
||||
|
||||
[JsonIgnore] public DateTime LastUpdate { get; set; }
|
||||
|
||||
[JsonIgnore] public decimal TempQta { get; set; }
|
||||
}
|
||||
@@ -7,6 +7,9 @@ public class ModalRef
|
||||
public Modal SpinnerModal { get; set; } = default!;
|
||||
public Modal ViewLogModal { get; set; } = default!;
|
||||
public Modal SelectPrinterModal { get; set; } = default!;
|
||||
public Modal SelectReceiptModal { get; set; } = default!;
|
||||
public Modal PermissionModal { get; set; } = default!;
|
||||
public Modal RicalcolaImporto { get; set; } = default!;
|
||||
|
||||
public bool SpinnerModalSign { get; set; }
|
||||
}
|
||||
@@ -9,18 +9,25 @@ public interface IDataStorage
|
||||
Task<List<SospesiClienteDTO>> RetrieveSospesi(string codVdes);
|
||||
Task<List<SospesiClienteDTO>?> RetrieveAllSospesi();
|
||||
Task<List<PaymentDataDTO>?> RetrieveAllPaymentData();
|
||||
List<FileInfo> RetrieveAllReceipts();
|
||||
|
||||
string? GetFilePath(string fileName, bool signed = false);
|
||||
string GetDirectoryPath(bool signed = false);
|
||||
string? GetCertificatePath(string fileName);
|
||||
FileStream GetFile(string filePath);
|
||||
FileStream GetFileOutput(string fileName, bool signed = false);
|
||||
Task OpenReceiptFile(string fileName);
|
||||
Task OpenFile(string fileName, bool signed = false);
|
||||
|
||||
Task WriteReceiptTextAsync(string fileName, string content);
|
||||
|
||||
List<FileInfo>? RetrieveAllFile(bool signed, bool certificate);
|
||||
FileInfo? RetrieveLogFile();
|
||||
Task OpenLogFile(string? filename);
|
||||
|
||||
Task<string> ReadLogFile(string? filename);
|
||||
Task<string> ReadReceiptFile(string? fileName);
|
||||
|
||||
void ClearOriginalDocumentsDirectory();
|
||||
void ClearSignedDocuments();
|
||||
}
|
||||
10
ConSegna.Shared/Core/Interfaces/IGenericSystemService.cs
Normal file
10
ConSegna.Shared/Core/Interfaces/IGenericSystemService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace ConSegna.Shared.Core.Interfaces;
|
||||
|
||||
public interface IGenericSystemService
|
||||
{
|
||||
string GetCurrentAppVersion();
|
||||
void OpenSettings();
|
||||
void CloseApp();
|
||||
|
||||
DateTime DataApp { get; set; }
|
||||
}
|
||||
@@ -2,5 +2,6 @@
|
||||
|
||||
public interface IGeolocationService
|
||||
{
|
||||
Task<bool> RequestAccess();
|
||||
Task<string> GetCoordinateOfCurrentLocation();
|
||||
}
|
||||
8
ConSegna.Shared/Core/Interfaces/ILogReceiptsService.cs
Normal file
8
ConSegna.Shared/Core/Interfaces/ILogReceiptsService.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using ConSegna.Shared.Core.Dto;
|
||||
|
||||
namespace ConSegna.Shared.Core.Interfaces;
|
||||
|
||||
public interface ILogReceiptsService
|
||||
{
|
||||
Task AddReceipt(List<SospesiClienteDTO> documentiPagati, decimal incassato, decimal daIncassare, string paymentMethod);
|
||||
}
|
||||
8
ConSegna.Shared/Core/Interfaces/IUtilityFile.cs
Normal file
8
ConSegna.Shared/Core/Interfaces/IUtilityFile.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace ConSegna.Shared.Core.Interfaces;
|
||||
|
||||
public interface IUtilityFile
|
||||
{
|
||||
string ComposeFileName(string codDtip, DateTime dataDoc, string serDoc, int numDoc, string codAnag);
|
||||
|
||||
DateTime? DetectDataDocFromFileName(string fileName);
|
||||
}
|
||||
@@ -8,20 +8,18 @@ using IntegryApiClient.Core.Domain.RestClient.Contacts;
|
||||
|
||||
namespace ConSegna.Shared.Core.Services;
|
||||
|
||||
public class IntegryApiService(IIntegryApiRestClient integryApiRestClient, IUserSession userSession)
|
||||
: IIntegryApiService
|
||||
public class IntegryApiService(
|
||||
IIntegryApiRestClient integryApiRestClient,
|
||||
IUserSession userSession,
|
||||
IGenericSystemService systemService
|
||||
) : IIntegryApiService
|
||||
{
|
||||
public Task<List<DatiClientiDTO>> GetDatiConsegne()
|
||||
{
|
||||
var requestDataDto = new RequestDataDTO
|
||||
{
|
||||
Username = userSession.User.Username,
|
||||
#if DEBUG
|
||||
DataDoc = new DateTime(2025, 06, 04)
|
||||
//DataDoc = DateTime.Today
|
||||
#else
|
||||
DataDoc = DateTime.Today
|
||||
#endif
|
||||
DataDoc = systemService.DataApp
|
||||
};
|
||||
|
||||
return integryApiRestClient.AuthorizedPost<List<DatiClientiDTO>>("consegna/getDatiConsegne", requestDataDto)!;
|
||||
|
||||
83
ConSegna.Shared/Core/Services/LogReceiptsService.cs
Normal file
83
ConSegna.Shared/Core/Services/LogReceiptsService.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System.Text;
|
||||
using ConSegna.Shared.Core.Dto;
|
||||
using ConSegna.Shared.Core.Interfaces;
|
||||
|
||||
namespace ConSegna.Shared.Core.Services;
|
||||
|
||||
public class LogReceiptsService(
|
||||
IDataStorage dataStorage)
|
||||
: ILogReceiptsService
|
||||
{
|
||||
private const string BaseFileName = "_receipts.txt";
|
||||
|
||||
public Task AddReceipt(List<SospesiClienteDTO> documentiPagati, decimal incassato, decimal daIncassare, string paymentMethod)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var fileName = $"{DateTime.Today:yyyyMMdd}{BaseFileName}";
|
||||
|
||||
await dataStorage.WriteReceiptTextAsync(
|
||||
fileName, ComposeReceiptText(documentiPagati, incassato, daIncassare, paymentMethod)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private static string ComposeReceiptText(
|
||||
List<SospesiClienteDTO> documentiPagati,
|
||||
decimal incassato,
|
||||
decimal daIncassare,
|
||||
string paymentMethod)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
const string separator = "------------------------------------";
|
||||
var lineWidth = separator.Length;
|
||||
|
||||
// HEADER
|
||||
var header = $"----Incasso-del-{DateTime.Now:g}----";
|
||||
sb.AppendLine(header.PadRight(lineWidth));
|
||||
|
||||
// TITOLO COLONNE
|
||||
const string col1 = "Documento";
|
||||
const string col2 = "Tot. Pagato";
|
||||
|
||||
sb.AppendLine(ComposeTwoColumns(col1, col2, lineWidth));
|
||||
|
||||
// DOCUMENTI PAGATI
|
||||
foreach (var doc in documentiPagati)
|
||||
{
|
||||
var docLine = $"{doc.CodDtip} n.{doc.NumDoc}";
|
||||
var importo = $"{doc.ImportoPagato:C}";
|
||||
|
||||
sb.AppendLine(ComposeTwoColumns(docLine, importo, lineWidth));
|
||||
sb.AppendLine($"del {doc.DataDoc:d}".PadRight(lineWidth));
|
||||
sb.AppendLine(separator);
|
||||
}
|
||||
|
||||
// RIEPILOGO
|
||||
sb.AppendLine(ComposeTwoColumns("Incassato", incassato.ToString("C"), lineWidth));
|
||||
sb.AppendLine(ComposeTwoColumns("Da incassare", daIncassare.ToString("C"), lineWidth));
|
||||
sb.AppendLine(separator);
|
||||
|
||||
var totIncasso = incassato > 0 ? incassato - daIncassare : 0;
|
||||
var label = totIncasso < 0 ? "Differenza" : "Resto";
|
||||
|
||||
sb.AppendLine(ComposeTwoColumns(label, totIncasso.ToString("C"), lineWidth));
|
||||
sb.AppendLine($"Modalità - {paymentMethod}".PadRight(lineWidth));
|
||||
sb.AppendLine();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string ComposeTwoColumns(string left, string right, int totalWidth)
|
||||
{
|
||||
const int spacing = 1;
|
||||
var leftWidth = totalWidth - right.Length - spacing;
|
||||
|
||||
if (leftWidth < left.Length)
|
||||
leftWidth = left.Length + spacing;
|
||||
|
||||
return left.PadRight(leftWidth) + right;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using ConSegna.Shared.Components.SingleElements
|
||||
@using ConSegna.Shared.Components.SingleElements.Modal
|
||||
@using Microsoft.JSInterop
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@@ -14,9 +16,11 @@
|
||||
@using IntegryApiClient.Core.Domain.Abstraction.Contracts.Storage
|
||||
@using ConSegna.Shared.Core.Dto
|
||||
@using ConSegna.Shared.Core.Helpers
|
||||
@using ConSegna.Shared.Core.Interfaces
|
||||
@using Microsoft.AspNetCore.Components
|
||||
@using static InteractiveRenderSettings
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUserSession UserSession
|
||||
@inject ILocalStorage LocalStorage
|
||||
@inject IGenericSystemService SystemService
|
||||
@@ -4,7 +4,7 @@
|
||||
font-weight: 400;
|
||||
line-height: 1.8;
|
||||
color: black;
|
||||
background-color: var(--background-color)
|
||||
background-color: var(--background-color);
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
@@ -17,11 +17,13 @@ a, .btn-link {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem var(--primary-color); }
|
||||
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
|
||||
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem var(--primary-color);
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: calc(3rem + 1.1rem);
|
||||
padding-bottom: 6rem;
|
||||
padding-top: 5rem;
|
||||
}
|
||||
|
||||
.modalSearch-searchBox {
|
||||
@@ -58,7 +60,9 @@ a, .btn-link {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.hide-header { display: none; }
|
||||
.hide-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.input-body-modal {
|
||||
padding-top: 0 !important;
|
||||
@@ -68,11 +72,17 @@ h1:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.valid.modified:not([type=checkbox]) { outline: 1px solid #26b050; }
|
||||
.valid.modified:not([type=checkbox]) {
|
||||
outline: 1px solid #26b050;
|
||||
}
|
||||
|
||||
.invalid { outline: 1px solid #e50000; }
|
||||
.invalid {
|
||||
outline: 1px solid #e50000;
|
||||
}
|
||||
|
||||
.validation-message { color: #e50000; }
|
||||
.validation-message {
|
||||
color: #e50000;
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
@@ -99,9 +109,13 @@ h1:focus {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.blazor-error-boundary::after { content: "An error has occurred." }
|
||||
.blazor-error-boundary::after {
|
||||
content: "An error has occurred."
|
||||
}
|
||||
|
||||
.status-bar-safe-area { display: none; }
|
||||
.status-bar-safe-area {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
/*text-align: center;*/
|
||||
@@ -109,11 +123,17 @@ h1:focus {
|
||||
color: var(--darker-color);
|
||||
}
|
||||
|
||||
.carousel-control-next, .carousel-control-prev { border-radius: 15px !important; }
|
||||
.carousel-control-next, .carousel-control-prev {
|
||||
border-radius: 15px !important;
|
||||
}
|
||||
|
||||
.carousel-item-next, .carousel-item-prev { border-radius: 15px !important; }
|
||||
.carousel-item-next, .carousel-item-prev {
|
||||
border-radius: 15px !important;
|
||||
}
|
||||
|
||||
.carousel-item-start, .carousel-item-end { border-radius: 15px !important; }
|
||||
.carousel-item-start, .carousel-item-end {
|
||||
border-radius: 15px !important;
|
||||
}
|
||||
|
||||
@supports (-webkit-touch-callout: none) {
|
||||
.status-bar-safe-area {
|
||||
@@ -127,7 +147,9 @@ h1:focus {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.modal { padding-top: env(safe-area-inset-top); }
|
||||
.modal {
|
||||
padding-top: env(safe-area-inset-top);
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 3rem !important;
|
||||
@@ -139,13 +161,15 @@ h1:focus {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.flex-column, .navbar-brand { padding-left: env(safe-area-inset-left); }
|
||||
.flex-column, .navbar-brand {
|
||||
padding-left: env(safe-area-inset-left);
|
||||
}
|
||||
}
|
||||
|
||||
.line-separator {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: 1px solid hsl(from var(--disable-color) h s 90%);
|
||||
border: .05rem solid hsl(from var(--disable-color) h s 90%);
|
||||
}
|
||||
|
||||
/*Spinner*/
|
||||
@@ -179,10 +203,14 @@ h1:focus {
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
.loader:after { animation-duration: 4s; }
|
||||
.loader:after {
|
||||
animation-duration: 4s;
|
||||
}
|
||||
|
||||
@keyframes l24 {
|
||||
100% { transform: rotate(1turn) }
|
||||
100% {
|
||||
transform: rotate(1turn)
|
||||
}
|
||||
}
|
||||
|
||||
/*Checkbox*/
|
||||
@@ -331,3 +359,46 @@ h1:focus {
|
||||
--s: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/*Custom*/
|
||||
|
||||
.modal-fullscreen > .modal-content {
|
||||
border-radius: unset !important;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
border-radius: 1.5em !important;
|
||||
border: unset !important;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
--bs-backdrop-opacity: 0.2 !important;
|
||||
}
|
||||
|
||||
/*Ripple*/
|
||||
.ripple-container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
.ripple {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
transform: scale(0);
|
||||
animation: ripple-effect 0.6s linear;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes ripple-effect {
|
||||
to {
|
||||
transform: scale(4);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ripple-white .ripple {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
@@ -22,3 +22,41 @@ observer.observe(document.body, {
|
||||
subtree: false
|
||||
});
|
||||
|
||||
(function () {
|
||||
// Ascoltiamo l'evento 'mousedown' su tutto il documento
|
||||
document.addEventListener('mousedown', function (event) {
|
||||
|
||||
// Cerca se l'elemento cliccato (o un suo genitore) ha la classe .ripple-container
|
||||
const target = event.target.closest('.ripple-container');
|
||||
|
||||
if (target) {
|
||||
createRipple(event, target);
|
||||
}
|
||||
});
|
||||
|
||||
function createRipple(event, element) {
|
||||
const circle = document.createElement("span");
|
||||
const diameter = Math.max(element.clientWidth, element.clientHeight);
|
||||
const radius = diameter / 2;
|
||||
|
||||
const rect = element.getBoundingClientRect();
|
||||
|
||||
circle.style.width = circle.style.height = `${diameter}px`;
|
||||
circle.style.left = `${event.clientX - rect.left - radius}px`;
|
||||
circle.style.top = `${event.clientY - rect.top - radius}px`;
|
||||
circle.classList.add("ripple");
|
||||
|
||||
// Rimuovi l'elemento dal DOM alla fine dell'animazione per non intasare la memoria
|
||||
const ripple = element.getElementsByClassName("ripple")[0];
|
||||
if (ripple) {
|
||||
ripple.remove();
|
||||
}
|
||||
|
||||
element.appendChild(circle);
|
||||
|
||||
// Pulizia automatica dopo 600ms (durata animazione CSS)
|
||||
setTimeout(() => {
|
||||
circle.remove();
|
||||
}, 600);
|
||||
}
|
||||
})();
|
||||
@@ -15,7 +15,7 @@ public class DataStorage(IIntegryApiService integryApiService) : IDataStorage
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<List<SospesiClienteDTO>> RetrieveSospesi(string cliente)
|
||||
public Task<List<SospesiClienteDTO>> RetrieveSospesi(string codVdes)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -30,6 +30,11 @@ public class DataStorage(IIntegryApiService integryApiService) : IDataStorage
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public List<FileInfo> RetrieveAllReceipts()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string? GetFilePath(string fileName, bool signed = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@@ -55,22 +60,32 @@ public class DataStorage(IIntegryApiService integryApiService) : IDataStorage
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task OpenReceiptFile(string fileName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task OpenFile(string fileName, bool signed = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task WriteReceiptTextAsync(string fileName, string content)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public List<FileInfo>? RetrieveAllFile(bool signed, bool certificate)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public FileInfo RetrieveLogFile()
|
||||
public FileInfo? RetrieveLogFile()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task OpenLogFile(string filename)
|
||||
public Task OpenLogFile(string? filename)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -80,6 +95,11 @@ public class DataStorage(IIntegryApiService integryApiService) : IDataStorage
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> ReadReceiptFile(string? fileName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void ClearOriginalDocumentsDirectory()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
@@ -4,6 +4,11 @@ namespace ConSegna.Web.Services;
|
||||
|
||||
public class GeolocationService : IGeolocationService
|
||||
{
|
||||
public Task<bool> RequestAccess()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<string> GetCoordinateOfCurrentLocation()
|
||||
{
|
||||
return "Posizione non rilevata";
|
||||
|
||||
Reference in New Issue
Block a user