This commit is contained in:
mmrbnjd
2024-05-16 23:40:32 +03:30
parent 354316abba
commit 3ca7f9deb0
25 changed files with 7727 additions and 101 deletions

View File

@@ -7,6 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Blazor.PersianDatePicker" Version="2.1.0" />
<PackageReference Include="Melipayamak.RestClient" Version="1.0.0" /> <PackageReference Include="Melipayamak.RestClient" Version="1.0.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" /> <PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
@@ -34,7 +35,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="Service"> <Reference Include="Service">
<HintPath>..\..\..\LocalGit\TaxPayerTools\Service\bin\Debug\Service.dll</HintPath> <HintPath>..\..\Dlls\Service.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>

View File

@@ -38,6 +38,13 @@ namespace Back.Controllers
[HttpPost("Add")] [HttpPost("Add")]
public async Task<ActionResult<int>> Add([FromBody] NUInvoiceDTO item) public async Task<ActionResult<int>> Add([FromBody] NUInvoiceDTO item)
{ {
if(string.IsNullOrEmpty(item.InvoiceDate))
item.InvoiceDate = DateTime.Now.ConvertMiladiToShamsi();
if (string.IsNullOrEmpty(item.InvoicIssueDate))
item.InvoicIssueDate = DateTime.Now.ConvertMiladiToShamsi();
if (!ModelState.IsValid) if (!ModelState.IsValid)
return BadRequest(item); return BadRequest(item);
@@ -113,11 +120,20 @@ namespace Back.Controllers
//-----change invoice //-----change invoice
if (!string.IsNullOrEmpty(item.Title))
invoice.Title = item.Title; invoice.Title = item.Title;
invoice.PatternID = item.PatternID; invoice.PatternID = item.PatternID;
if(item.CustomerID > 0)
invoice.CustomerID = item.CustomerID; invoice.CustomerID = item.CustomerID;
if (!string.IsNullOrEmpty(item.InvoicIssueDate))
invoice.InvoicIssueDate = item.InvoicIssueDate; invoice.InvoicIssueDate = item.InvoicIssueDate;
if (!string.IsNullOrEmpty(item.InvoiceDate))
invoice.InvoiceDate = item.InvoiceDate; invoice.InvoiceDate = item.InvoiceDate;
invoice.Des = item.Des; invoice.Des = item.Des;
invoice.LastChangeUserID = Convert.ToInt32(UserID); invoice.LastChangeUserID = Convert.ToInt32(UserID);
@@ -341,5 +357,10 @@ namespace Back.Controllers
return NoContent(); return NoContent();
} }
[HttpGet("GetPatterns")]
public async Task<ActionResult<List<IdName<int>>>> GetPatterns()
{
return Ok(await _servTaxPayer.GetPatterns());
}
} }
} }

View File

@@ -8,9 +8,11 @@ namespace Back.Services
public class servTaxPayer public class servTaxPayer
{ {
private readonly IAsyncRepository<SentTax> _repoSentTax; private readonly IAsyncRepository<SentTax> _repoSentTax;
public servTaxPayer(IAsyncRepository<SentTax> repoSentTax) private readonly IAsyncRepository<Pattern> _repoPattern;
public servTaxPayer(IAsyncRepository<SentTax> repoSentTax, IAsyncRepository<Pattern> repoPattern)
{ {
_repoSentTax = repoSentTax; _repoSentTax = repoSentTax;
_repoPattern = repoPattern;
} }
public async Task<bool> ExistSuccessfulorSendorpendingInvoiceinCompanyID(int CompanyID) public async Task<bool> ExistSuccessfulorSendorpendingInvoiceinCompanyID(int CompanyID)
{ {
@@ -27,6 +29,10 @@ namespace Back.Services
&& (w.SentStatus == SentStatus.Successful || w.SentStatus == SentStatus.Send || w.SentStatus == SentStatus.pending) && (w.SentStatus == SentStatus.Successful || w.SentStatus == SentStatus.Send || w.SentStatus == SentStatus.pending)
&& w.invoice.CompanyID != CompanyID).AnyAsync(); && w.invoice.CompanyID != CompanyID).AnyAsync();
} }
public async Task<List<IdName<int>>> GetPatterns()
{
return await _repoPattern.Get(w=>w.Status).Select(s => new IdName<int> { ID = s.ID, Title = s.Title }).ToListAsync();
} }
} }
}

View File

@@ -0,0 +1,48 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFrameworks>net5.0</TargetFrameworks>
<Version>3.3.0</Version>
<LangVersion>latest</LangVersion>
<NoWarn>$(NoWarn);NU1701;1702;1591;NU1602;CS8609;CS8610;CS8619;CS8632</NoWarn>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<Authors>Farshad Davoudi</Authors>
<Title>Blazor.PersianDatePicker</Title>
<Company>Bit</Company>
<Description>
A free Jalali (Persian) and Gregorian (Miladi) dual datepicker library for Blazor applications
</Description>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<!-- Add README.md to nuget package -->
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryURL>https://github.com/farshaddavoudi/Blazor.PersianDatePicker</RepositoryURL>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DebugType>portable</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb;.xml</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedAllSources>True</EmbedAllSources>
<DebugType>portable</DebugType>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<SupportedPlatform Include="browser" />
<!-- Add README.md to nuget package -->
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="5.0.0" />
<PackageReference Include="Delegate.SassBuilder" Version="1.4.0" />
<PackageReference Include="SourceLink.Embed.AllSourceFiles" Version="2.8.3" PrivateAssets="all" />
<PackageReference Include="SourceLink.Copy.PdbFiles" Version="2.8.3" PrivateAssets="All" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,10 @@
// ReSharper disable CheckNamespace
namespace Blazor.PersianDatePicker
{
public enum Align
{
Right,
Left
}
}

View File

@@ -0,0 +1,27 @@
// ReSharper disable once CheckNamespace
namespace Blazor.PersianDatePicker
{
public enum Calendar
{
/// <summary>
/// Both Jalali (Persian) and Miladi (Gregorian) calendars, with default set to Jalali
/// </summary>
DualModeJalaliDefault,
/// <summary>
/// Both Jalali (Persian) and Miladi (Gregorian) calendars, with default set to Miladi
/// </summary>
DualModeMiladiDefault,
/// <summary>
/// Only Jalali (Persian) calendar
/// </summary>
SingleModeJalali,
/// <summary>
/// Only Miladi (Gregorian) calendar
/// </summary>
SingleModeMiladi
}
}

View File

@@ -0,0 +1,48 @@
using System.ComponentModel.DataAnnotations;
// ReSharper disable InconsistentNaming
// ReSharper disable once CheckNamespace
namespace Blazor.PersianDatePicker
{
public enum DateFormat
{
/// <summary>
/// e.g. 1400/01/01
/// </summary>
[Display(Name = "YYYY/MM/DD")]
yyyy_slash_MM_slash_dd,
/// <summary>
/// e.g. 1400-01-01
/// </summary>
[Display(Name = "YYYY-MM-DD")]
yyyy_dash_MM_dash_dd
}
public static class DateFormatExtensions
{
public static string GetCSharpFormat(this DateFormat format)
{
if (format == DateFormat.yyyy_slash_MM_slash_dd)
return "yyyy/MM/dd";
if (format == DateFormat.yyyy_dash_MM_dash_dd)
return "yyyy-MM-dd";
return null;
}
public static string GetSeparator(this DateFormat format)
{
if (format == DateFormat.yyyy_slash_MM_slash_dd)
return "/";
if (format == DateFormat.yyyy_dash_MM_dash_dd)
return "-";
return null;
}
}
}

View File

@@ -0,0 +1,22 @@
// ReSharper disable CheckNamespace
namespace Blazor.PersianDatePicker
{
public enum DigitType
{
/// <summary>
/// For dual calendar mode, will change based on current calendar
/// </summary>
BasedOnCalendar,
/// <summary>
/// e.g. ۱۴۰۰/۰۱/۱۱
/// </summary>
Persian,
/// <summary>
/// e.g. 1400/01/11
/// </summary>
English
}
}

View File

@@ -0,0 +1,11 @@
// ReSharper disable CheckNamespace
namespace Blazor.PersianDatePicker
{
public enum IconPosition
{
BasedOnAlign,
Right,
Left
}
}

View File

@@ -0,0 +1,23 @@
using System.ComponentModel.DataAnnotations;
// ReSharper disable CheckNamespace
namespace Blazor.PersianDatePicker
{
public enum PickerTheme
{
[Display(Name = "default-theme")]
Default,
[Display(Name = "dark-theme")]
Dark,
[Display(Name = "blue-theme")]
Blue,
[Display(Name = "cheerup-theme")]
Cheerup,
[Display(Name = "redblack-theme")]
RedBlack
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
namespace Blazor.PersianDatePicker.Extensions
{
public static class EnumExtensions
{
public static string? ToEnumDisplayName(this Enum value, bool showEnumStringIfNoDisplayName = true)
{
if (value == null)
throw new ArgumentNullException(nameof(value));
var displayName = value.GetType()
.GetMember(value.ToString())
.First()
?.GetCustomAttributes<DisplayAttribute>()
.FirstOrDefault()
?.GetName();
return displayName ?? (showEnumStringIfNoDisplayName ? value.ToString() : null);
}
}
}

View File

@@ -0,0 +1,44 @@
namespace Blazor.PersianDatePicker.Extensions
{
public static class StringExtensions
{
public static string EnglishToPersianDigits(this string str)
{
return str.Replace("0", "۰")
.Replace("1", "۱")
.Replace("2", "۲")
.Replace("3", "۳")
.Replace("4", "۴")
.Replace("5", "۵")
.Replace("6", "۶")
.Replace("7", "۷")
.Replace("8", "۸")
.Replace("9", "۹");
}
public static string PersianToEnglishDigits(this string str)
{
return str.Replace("۰", "0")
.Replace("۱", "1")
.Replace("۲", "2")
.Replace("۳", "3")
.Replace("۴", "4")
.Replace("۵", "5")
.Replace("۶", "6")
.Replace("۷", "7")
.Replace("۸", "8")
.Replace("۹", "9")
//iphone numeric
.Replace("٠", "0")
.Replace("١", "1")
.Replace("٢", "2")
.Replace("٣", "3")
.Replace("٤", "4")
.Replace("٥", "5")
.Replace("٦", "6")
.Replace("٧", "7")
.Replace("٨", "8")
.Replace("٩", "9");
}
}
}

View File

@@ -0,0 +1,402 @@
@using System.ComponentModel.DataAnnotations
@if (Visible)
{
<div class="datepicker_wrapp" style="@Style">
<input id="@Id"
name="@Name"
readonly="@ReadOnly"
disabled="@Disabled"
class="@_internalCssClass @_iconCssClass @CssClass"
placeholder="@Placeholder"
autocomplete="off"
maxlength="10"
value="@Value"
init-value="@Value"
@onchange="@Change" />
<span class="@_clearBtnCssClass" @onclick="@Clear">×</span>
</div>
}
@code
{
#nullable enable
private string? _internalCssClass;
private string? _iconCssClass;
private string? _clearBtnCssClass;
public FieldIdentifier FieldIdentifier { get; private set; }
private string? _value;
private bool _isJalaliCurrentCalendarType;
[CascadingParameter]
public EditContext? EditContext { get; set; }
[Parameter]
public virtual string? Value
{
get => _value;
set
{
if (!EqualityComparer<string>.Default.Equals(value, _value))
{
_value = value;
}
}
}
[Parameter]
public EventCallback<string> ValueChanged { get; set; }
/// <summary>
/// Html input element id attribute (Required)
/// </summary>
[Parameter, Required]
public string? Id { get; set; }
/// <summary>
/// Html input element name attribute (Optional)
/// </summary>
[Parameter]
public string? Name { get; set; }
/// <summary>
/// Control visibility of input
/// </summary>
[Parameter]
public bool Visible { get; set; } = true;
/// <summary>
/// Disabled make input disabled. Meaning only showing value and picker popup won't open
/// </summary>
[Parameter]
public bool Disabled { get; set; }
/// <summary>
/// Picker align relative to input
/// </summary>
[Parameter]
public Align PickerAlign { get; set; } = Align.Right;
/// <summary>
/// Show calendar icon on input
/// </summary>
[Parameter]
public bool ShowCalendarIcon { get; set; } = true;
/// <summary>
/// Calendar icon position relative to input
/// </summary>
[Parameter]
public IconPosition CalendarIconPosition { get; set; } = IconPosition.BasedOnAlign;
/// <summary>
/// Can be used in changing vertical position of picker popup relative to input
/// </summary>
[Parameter]
public double PickerOffsetTopPositionInPixels { get; set; } = 2;
/// <summary>
/// Initial value for input set on today
/// </summary>
[Parameter]
public bool InitialValueSetOnToday { get; set; }
/// <summary>
/// Calendar type for date picker including Dual, Single, etc
/// </summary>
[Parameter]
public Calendar CalendarType { get; set; } = Calendar.DualModeJalaliDefault;
/// <summary>
/// Control the digit type showing in input after selecting by picker
/// </summary>
[Parameter]
public DigitType DigitType { get; set; } = DigitType.BasedOnCalendar;
/// <summary>
/// Format of date to show in input after selecting by picker
/// </summary>
[Parameter]
public DateFormat DateFormat { get; set; } = DateFormat.yyyy_slash_MM_slash_dd;
/// <summary>
/// Prevent user select date before today
/// </summary>
[Parameter]
public bool MinDateSetOnToday { get; set; } = true;
[Parameter]
public string? Placeholder { get; set; }
/// <summary>
/// Set datepicker readonly
/// </summary>
[Parameter]
public bool ReadOnly { get; set; } = true;
/// <summary>
/// CSS class for input element
/// </summary>
[Parameter]
public string? CssClass { get; set; }
/// <summary>
/// Inline styles for input element
/// </summary>
[Parameter]
public string? Style { get; set; }
/// <summary>
/// Choose a theme for changing look and feel of picker
/// </summary>
[Parameter]
public PickerTheme Theme { get; set; } = PickerTheme.Default;
[Parameter]
public Expression<Func<string>>? ValueExpression { get; set; }
[Parameter]
public EventCallback<string> OnChange { get; set; }
[Parameter]
public EventCallback OnClear { get; set; }
[Inject] private IJSRuntime? JsRuntime { get; set; }
protected override async Task OnInitializedAsync()
{
if (string.IsNullOrEmpty(Id))
Id = "id" + new Random().Next(1000, 9999);
if (CalendarType == Calendar.DualModeJalaliDefault || CalendarType == Calendar.SingleModeJalali)
_isJalaliCurrentCalendarType = true;
else
_isJalaliCurrentCalendarType = false;
if (!ShowCalendarIcon)
{
_iconCssClass = "";
_clearBtnCssClass = "clear-btn right";
}
else
{
if (CalendarIconPosition == IconPosition.Left)
{
_iconCssClass = "persian-datepicker-left-icon";
_clearBtnCssClass = "clear-btn right";
}
else if (CalendarIconPosition == IconPosition.Right)
{
_iconCssClass = "persian-datepicker-right-icon";
_clearBtnCssClass = "clear-btn left";
}
else
{
if (PickerAlign == Align.Right)
{
_iconCssClass = "persian-datepicker-left-icon";
_clearBtnCssClass = "clear-btn right";
}
else
{
_iconCssClass = "persian-datepicker-right-icon";
_clearBtnCssClass = "clear-btn left";
}
}
}
if (InitialValueSetOnToday)
{
var dt = DateTime.Now;
_value = _isJalaliCurrentCalendarType
? GetPersianDateFromGregorianDate(dt)
: dt.ToString(DateFormat.GetCSharpFormat());
ModifyValueDigit();
await OnValueChanged();
}
_internalCssClass = Disabled ? "datepicker-disabled" : "blazor-datepicker";
await base.OnInitializedAsync();
}
public override Task SetParametersAsync(ParameterView parameters)
{
var result = base.SetParametersAsync(parameters);
if (EditContext != null && ValueExpression != null && FieldIdentifier.Model != EditContext.Model)
{
FieldIdentifier = FieldIdentifier.Create(ValueExpression);
EditContext.OnValidationStateChanged += ValidationStateChanged;
}
return result;
}
private void ValidationStateChanged(object? sender, ValidationStateChangedEventArgs e)
{
StateHasChanged();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var calendarType = CalendarType == Calendar.SingleModeJalali || CalendarType == Calendar.DualModeJalaliDefault
? "persian"
: "gregorian";
bool enableSwitchCalendar = CalendarType == Calendar.DualModeJalaliDefault || CalendarType == Calendar.DualModeMiladiDefault;
bool? hasExplicitDigitType = DigitType != DigitType.BasedOnCalendar;
string digitType = "float";
if (DigitType == DigitType.Persian)
digitType = "fa";
else if (DigitType == DigitType.English)
digitType = "en";
var minDate = MinDateSetOnToday ? "today" : null;
await JsRuntime!.InvokeVoidAsync("blazorReady",
DotNetObjectReference.Create(this),
Id!,
calendarType,
enableSwitchCalendar,
hasExplicitDigitType,
digitType,
InitialValueSetOnToday,
DateFormat.ToEnumDisplayName()!,
minDate ?? string.Empty,
PickerAlign.ToString().ToLower(),
PickerOffsetTopPositionInPixels,
Theme.ToEnumDisplayName()!);
await base.OnAfterRenderAsync(true);
}
await base.OnAfterRenderAsync(false);
}
protected async Task Change(ChangeEventArgs args)
{
Value = $"{args.Value}";
await ValueChanged.InvokeAsync(Value);
EditContext?.NotifyFieldChanged(FieldIdentifier);
await OnChange.InvokeAsync(Value);
}
[JSInvokable]
public async Task SetDate(long? timestamp, string elementId, bool switchingCalendar = false)
{
if (elementId != Id)
return;
if (timestamp != null)
{
var dt = new DateTime(1970, 1, 1, 0, 0, 0, 0)
.AddSeconds(Math.Round((long)timestamp / 1000d)).ToLocalTime();
_value = _isJalaliCurrentCalendarType
? GetPersianDateFromGregorianDate(dt)
: dt.ToString(DateFormat.GetCSharpFormat());
}
if (switchingCalendar)
{
_isJalaliCurrentCalendarType = !_isJalaliCurrentCalendarType;
if (_isJalaliCurrentCalendarType)
{
// Change from en to fa: 2021/04/03 => 1400/05/02
var dt = Convert.ToDateTime(_value);
_value = GetPersianDateFromGregorianDate(dt);
}
else
{
// Change from fa to en: 1400/05/05 => 2021/01/05
// Convert to Miladi
if (_value != null)
{
DateTime dt = DateTime.Parse(_value, new CultureInfo("fa-IR"));
// Get Date
_value = dt.ToString(DateFormat.GetCSharpFormat());
}
}
}
ModifyValueDigit();
await OnValueChanged();
}
[JSInvokable]
public async Task SetToday(string elementId)
{
var dt = DateTime.Today;
_value = _isJalaliCurrentCalendarType
? GetPersianDateFromGregorianDate(dt)
: dt.ToString(DateFormat.GetCSharpFormat());
ModifyValueDigit();
await OnValueChanged();
}
private void ModifyValueDigit()
{
if (DigitType == DigitType.Persian)
_value = _value?.EnglishToPersianDigits();
else if (DigitType == DigitType.English)
_value = _value?.PersianToEnglishDigits();
else if (DigitType == DigitType.BasedOnCalendar)
_value = _isJalaliCurrentCalendarType ? _value?.EnglishToPersianDigits() : _value?.PersianToEnglishDigits();
}
private async Task OnValueChanged()
{
await ValueChanged.InvokeAsync(_value);
EditContext?.NotifyFieldChanged(FieldIdentifier);
await OnChange.InvokeAsync(Value);
}
private string GetPersianDateFromGregorianDate(DateTime dt)
{
PersianCalendar pc = new PersianCalendar();
return $"{pc.GetYear(dt):D2}{DateFormat.GetSeparator()}{pc.GetMonth(dt):D2}{DateFormat.GetSeparator()}{pc.GetDayOfMonth(dt):D2}";
}
private async Task Clear()
{
await ValueChanged.InvokeAsync(string.Empty);
EditContext?.NotifyFieldChanged(FieldIdentifier);
await OnClear.InvokeAsync();
}
}

View File

@@ -0,0 +1,7 @@
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using Microsoft.AspNetCore.Components.Forms
@using System.Linq.Expressions
@using System.Globalization
@using Blazor.PersianDatePicker.Extensions

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

142
README.md Normal file
View File

@@ -0,0 +1,142 @@
# Blazor.PersianDatePicker
[![NuGet Version](https://img.shields.io/nuget/v/Blazor.PersianDatePicker.svg?style=flat)](https://www.nuget.org/packages/Blazor.PersianDatePicker/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://raw.githubusercontent.com/farshaddavoudi/Blazor.PersianDatePicker/master/LICENSE)
<img src="https://github.com/fericode/Blazor.PersianDatePicker/blob/master/screenshot.png">
*After v2.0.0:*
<img src="https://github.com/fericode/Blazor.PersianDatePicker/blob/master/screenshot2.png">
*Important fix in v3.2.0:*
- When we set the bound parameter value to some date by code (for example in `OnInitialize` method of our page) and then click on the input, the selected date in the datepicker was always today, not that date. It is resolved now. Thanks to [@EsmaeelAmarloo](https://github.com/EsmaeelAmarloo) for creating [the issue](https://github.com/farshaddavoudi/Blazor.PersianDatePicker/issues/60#issuecomment-1820790657).
## Compatibility:
It is compatible and installable on all .NET5, .NET6, .NET7 and .NET8 Blazor projects
## Usage:
1- Install **Blazor.PersianDatePicker** from Nuget.org
2- Add `<script src="_content/Blazor.PersianDatePicker/datepicker.min.js" type="text/javascript"></script>` to your **index.html** or **_Host.cshtml** or **App.razor** *(in .NET8)*
3- Add `<link href="_content/Blazor.PersianDatePicker/datepicker.css" rel="stylesheet" />` to your **index.html** or **_Host.cshtml** or **App.razor** *(in .NET8)*
4- Add `@using Blazor.PersianDatePicker` to **_imports.razor**
5- Use the component **InputPersianDatePicker**
## Options:
```csharp
<InputPersianDatePicker
// Html input element id attribute
Id="myInputDatePicker" //Optional
// Bind input value to local variable or dto etc
@bind-Value="_myComponentField"
// Html input element name attribute
Name="myInputName" //Optional
// Control visibility of input
Visible="true" //Default: true
// Disabled make input disabled. This means only showing value and the picker popup won't open
Disabled="false" //Default: false
// Readonly make input readonly. This means the user cannot change the picker value e.g. by typing
ReadOnly="true" //Default: true
// Picker'align relative to input
// Options: Align.Right | Align.Left
PickerAlign="Align.Right" //Default: Align.Right
// Show calendar icon on text input
ShowCalendarIcon="true" //Default: true
// Calendar icon position relative to input
// Options: IconPosition.BasedOnAlign | IconPosition.Left | IconPosition.Right
CalendarIconPosition="IconPosition.BasedOnAlign" //Default: IconPosition.BasedOnAlign
// Can be used in changing the vertical position of the picker popup relative to the input
PickerOffsetTopPositionInPixels="2" //Default: 2
// Initial value for the input set today
InitialValueSetOnToday="false" //Default: false
// Calendar type for date picker including Dual, Single, etc
// Options: Calendar.DualModeJalaliDefault | Calendar.DualModeMiladiDefault | Calendar.SingleModeJalali | Calendar.SingleModeMiladi
CalendarType="Calendar.DualModeJalaliDefault" //Default: Calendar.DualModeJalaliDefault
// Control the digit type showing in the input after selecting by the picker
// Options: DigitType.BasedOnCalendar | DigitType.Persian | DigitType.English
DigitType="DigitType.BasedOnCalendar" //Default: DigitType.BasedOnCalendar
// Format of date to show in the input after selecting by picker, e.g. 1400/01/01 or 1400-01-01
// Options: DateFormat.yyyy_slash_MM_slash_dd | DateFormat.yyyy_dash_MM_dash_dd
DateFormat="DateFormat.yyyy_slash_MM_slash_dd" //Default: DateFormat.yyyy_slash_MM_slash_dd
// Prevent the user from selecting a date before today
MinDateSetOnToday="true" //Default: true
// Input placeholder
Placeholder="Select date"
// CSS class for input element
CssClass="form-control"
// Inline styles for input element
Style="border:1px solid red; width:50%"
// Choose a theme for changing the look and feel of the picker
// Options: PickerTheme.Default | PickerTheme.Dark | PickerTheme.Blue | PickerTheme.Cheerup | PickerTheme.RedBlack
// Themes can be seen in the image
Theme="PickerTheme.Default"
// Input change event
OnChange="@(() => Console.WriteLine("OK"))"
// Input text clear event (by pressing close button)
OnClear="@(() => Console.WriteLine("Cleared"))" />
```
> #### 💡 You can add multi-instances of InputPersianDatePicker components on a page and all of them work independently without any problem
## Sample template for fast usage:
#### Copy from here then paste in your project; change some options and you're done.
```razor
<InputPersianDatePicker Id="myInputDatePicker"
@bind-Value="_variable4"
Name="myInputName"
Visible="true"
Disabled="false"
PickerAlign="Align.Right"
PickerOffsetTopPositionInPixels="1"
InitialValueSetOnToday="false"
CalendarType="Calendar.SingleModeJalali"
DigitType="DigitType.BasedOnCalendar"
DateFormat="DateFormat.yyyy_slash_MM_slash_dd"
MinDateSetOnToday="true"
Placeholder="Select date"
CssClass="form-control"
Style="border:1px solid green; width:20%; float:right"
Theme="PickerTheme.RedBlack"
OnChange="@(() => Console.WriteLine("OK"))" />
```
## Performance:
* `js` size (gzipped) ⇒ **35 kb**
* `css` size (gzipped) ⇒ **5 kb**
* `dll` size (gzipped) ⇒‌ **9 kb**
## Special Thanks:
*This project is ported from [pwt.datepicker](https://github.com/babakhani/pwt.datepicker) project with a lot of customizations and optimizations for easy and fast use for Blazor applications. Therefore, I appreciate the great effort of Reza Babakhani @babakhani and all contributors of that project*

View File

@@ -22,23 +22,23 @@ namespace Shared.DTOs
[Display(Name = "شناسه")] [Display(Name = "شناسه")]
public int ID { get; set; } public int ID { get; set; }
[Display(Name = "عنوان")] [Display(Name = "عنوان")]
public string Title { get; set; } public string Title { get; set; }//
public InvoiceType? invoiceType { get; set; } public InvoiceType? invoiceType { get; set; }//
public int? PatternID { get; set; } public int? PatternID { get; set; }//
public string? PatternTitle { get; set; } public string? PatternTitle { get; set; }//
[Display(Name = "نوع صورتحساب")] [Display(Name = "نوع صورتحساب")]
public string? invoiceTypeTitle { get; set; } public string? invoiceTypeTitle { get; set; }//
public int CustomerID { get; set; } public int CustomerID { get; set; }//
[Display(Name = "مشتری")] [Display(Name = "مشتری")]
public string CustomerName { get; set; } public string CustomerName { get; set; }//
public string? Udate { get; set; } public string? Udate { get; set; }
[Display(Name = "تاریخ صدور")] [Display(Name = "تاریخ صدور")]
public string InvoicIssueDate { get; set; } public string InvoicIssueDate { get; set; }//
public string InvoiceDate { get; set; } public string InvoiceDate { get; set; }//
public bool PreparedtoSendtoTax { get; set; } public bool PreparedtoSendtoTax { get; set; }
public string? Des { get; set; } public string? Des { get; set; }
//مجموع تخفیفات //مجموع تخفیفات
[Display(Name = "مجموع تخفیفات")] [Display(Name = "مجموع تخفیف")]
public decimal? tdis { get; set; } public decimal? tdis { get; set; }
//مجموع مالیات بر ارزش افزوده //مجموع مالیات بر ارزش افزوده
[MaxLength(18)] [MaxLength(18)]

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
@@ -10,6 +11,19 @@ namespace Shared
{ {
public static class ExMethod public static class ExMethod
{ {
public static string ShamciToFormatShamciinFront(this string str)
{
if (string.IsNullOrEmpty(str)) return "";
return str.Substring(0, 4) + "/" + str.Substring(4, 2) + "/" + str.Substring(6, 2);
}
public static string ConvertMiladiToShamsiinFront(this DateTime date)
{
PersianCalendar PersianCal = new PersianCalendar();
return PersianCal.GetYear(date).ToString("0000") +
PersianCal.GetMonth(date).ToString("00") +
PersianCal.GetDayOfMonth(date).ToString("00")
;
}
public static string GetEnumDisplayName(this Enum enumType) public static string GetEnumDisplayName(this Enum enumType)
{ {
return enumType.GetType().GetMember(enumType.ToString()) return enumType.GetType().GetMember(enumType.ToString())

View File

@@ -20,11 +20,13 @@
<select @bind="Cod.UnitID" class="form-control" aria-label="Default select example" id="inputUnitID"> <select @bind="Cod.UnitID" class="form-control" aria-label="Default select example" id="inputUnitID">
@if (Cod.UnitID > 0) @if (Cod.UnitID > 0)
{ {
<option value="0" style="color: #b5b5b5" selected>انتخاب کنید...</option> <option value="0" style="color: #b5b5b5">انتخاب کنید...</option>
} }
else else
{ {
<option value="0" style="color: #b5b5b5">انتخاب کنید...</option> <option value="0" style="color: #b5b5b5" selected>انتخاب کنید...</option>
} }
@if (Unitrequest != null) @if (Unitrequest != null)

View File

@@ -1,5 +1,6 @@
@using Front.Services @using Front.Services
@using Shared.DTOs @using Shared.DTOs
@using Shared
@inject HttpClientController hc; @inject HttpClientController hc;
<form> <form>
@* alert *@ @* alert *@
@@ -12,14 +13,14 @@
</div> </div>
<div class="row g-3"> <div class="row g-3">
<div class="form-group col-md-6"> <div class="form-group col-md-2">
<label class="col-sm-4 col-form-label" style="color:red" for="inputTitle">نام کالا</label> <label class="col-sm-4 col-form-label" style="color:red" for="inputTitle">عنوان</label>
<InputText @bind-Value="Cod.Title" type="text" class="form-control" id="inputTitle" placeholder="نام کالا" /> <InputText @bind-Value="invoice.Title" type="text" class="form-control" id="inputTitle" placeholder="عنوان" />
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-2">
<label class="col-sm-5 col-form-label" style="color:red" for="inputUnitID">واحد اندازه گیزی</label> <label class="col-sm-4 col-form-label" for="inputinvoiceTypeTitle">نوع</label>
<select @bind="Cod.UnitID" class="form-control" aria-label="Default select example" id="inputUnitID"> <select @bind="invoice.invoiceType" class="form-control" aria-label="Default select example" id="inputinvoiceTypeTitle">
@if (Cod.UnitID > 0) @if (!invoice.invoiceType.HasValue)
{ {
<option value="0" style="color: #b5b5b5" selected>انتخاب کنید...</option> <option value="0" style="color: #b5b5b5" selected>انتخاب کنید...</option>
} }
@@ -28,11 +29,42 @@
<option value="0" style="color: #b5b5b5">انتخاب کنید...</option> <option value="0" style="color: #b5b5b5">انتخاب کنید...</option>
} }
@if (Unitrequest != null)
@foreach (InvoiceType i in Enum.GetValues(typeof(InvoiceType)))
{ {
foreach (var item in Unitrequest)
if (invoice.invoiceType == i)
{ {
if (Cod.UnitID == item.ID) <option value="@i" selected>@i.GetEnumDisplayName()</option>
}
else
{
<option value="@i">@i.GetEnumDisplayName()</option>
}
}
</select>
</div>
<div class="form-group col-md-2">
<label class="col-sm-8 col-form-label" for="inputPatternID">الگو صورتحساب</label>
<select @bind="invoice.PatternID" class="form-control" aria-label="Default select example" id="inputPatternID">
@if (invoice.PatternID == null || invoice.PatternID ==0)
{
<option value="0" style="color: #b5b5b5" selected>انتخاب کنید...</option>
}
else
{
<option value="0" style="color: #b5b5b5">انتخاب کنید...</option>
}
@if (Patterns != null)
{
foreach (var item in Patterns)
{
if (invoice.PatternID == item.ID)
{ {
<option value="@item.ID" selected>@item.Title</option> <option value="@item.ID" selected>@item.Title</option>
} }
@@ -44,23 +76,79 @@
} }
</select> </select>
</div> </div>
<div class="form-group col-md-2">
<label class="col-sm-5 col-form-label" style="color:red" for="inputCustomerID">مشتری</label>
<select @bind="invoice.CustomerID" class="form-control" aria-label="Default select example" id="inputCustomerID">
@if (invoice.CustomerID == null || invoice.CustomerID == 0)
{
<option value="0" style="color: #b5b5b5" selected>انتخاب کنید...</option>
}
else
{
<option value="0" style="color: #b5b5b5">انتخاب کنید...</option>
}
@if (Cus != null)
{
foreach (var item in Cus)
{
if (invoice.CustomerID == item.ID)
{
<option value="@item.ID" selected>@item.CustomerName</option>
}
else
{
<option value="@item.ID">@item.CustomerName</option>
}
}
}
</select>
</div> </div>
<div class="form-group col-md-2">
<label class="col-sm-5 col-form-label" for="inputInvoicIssueDate">تاریخ صدور</label>
<InputText style=" text-align: center;" @bind-Value="invoice.InvoicIssueDate" type="text" class="form-control" id="inputInvoicIssueDate" placeholder="تاریخ صدور" />
</div>
<div class="form-group col-md-2">
<label class="col-sm-4 col-form-label" for="inputInvoiceDate">تاریخ</label>
<InputText style=" text-align: center;" @bind-Value="invoice.InvoiceDate" type="text" class="form-control" id="inputInvoiceDate" placeholder="تاریخ" />
</div>
</div>
<br /> <hr class="hr" />
<div class="row g-3"> <div class="row g-3">
<div class="col-md-6"> <Tabs NavStyle="NavStyle.VerticalUnderline">
<label class="col-sm-5 col-form-label">شناسه مالیاتی کالا</label> <Tab Title="آیتم ها" IsActive="true">
<InputText @bind-Value="Cod.TaxID" type="text" class="form-control" id="inputTaxID" placeholder="شناسه مالیاتی کالا" /> <Content>
<p class="ms-3">This is the placeholder content for the <b>Home</b> tab.</p>
</Content>
</Tab>
<Tab Title="پرداختی ها">
<Content>
<p class="ms-3">This is the placeholder content for the <b>Profile</b> tab.</p>
</Content>
</Tab>
</Tabs>
</div> </div>
<div class="col-md-6"> <hr class="hr" />
<label style="color:red" class="col-sm-5 col-form-label">% نرخ مالیات کالا</label> <br />
<NumberInput @bind-Value="Cod.TaxRate" type="text" class="form-control" id="inputTaxRate" placeholder="نرخ مالیات کالا" /> <div class="row g-3">
<div class="form-group col-md-8">
<label class="col-sm-4 col-form-label" for="inputdes">توضیحات</label>
<InputText @bind-Value="invoice.Des" type="text" class="form-control" id="inputdes" placeholder="توضیحات" />
</div>
<div class="form-group col-md-4">
<label class="col-sm-4 col-form-label" for="inputUdate">آخرین ویرایش</label>
<InputText style=" text-align: center;" @bind-Value="invoice.Udate" class="form-control" id="inputUdate" readonly />
</div> </div>
</div> </div>
</form> </form>
@if (Cod.ID == 0) @if (invoice.ID == 0)
{ {
<Button class="mt-3" Color="ButtonColor.Success" @onclick="OnClickAdd" Type="ButtonType.Button"> <Button class="mt-3" Color="ButtonColor.Success" @onclick="OnClickAdd" Type="ButtonType.Button">
جدید جدید
@@ -78,11 +166,14 @@ else
@code { @code {
// alert // alert
AlertColor alertColor = AlertColor.Primary; AlertColor alertColor = AlertColor.Primary;
IconName alertIconName = IconName.CheckCircleFill; IconName alertIconName = IconName.CheckCircleFill;
bool Hidealert = true; bool Hidealert = true;
string alertMessage = ""; string alertMessage = "";
[Parameter] public List<ForCustomerSearch> Cus { get; set; }
[Parameter] public List<IdName<int>> Patterns { get; set; }
[Parameter] public InvoiceDTO invoice { get; set; } [Parameter] public InvoiceDTO invoice { get; set; }
[Parameter] public EventCallback<ActionInResultComponent> OnMultipleOfThree { get; set; } [Parameter] public EventCallback<ActionInResultComponent> OnMultipleOfThree { get; set; }
// [Parameter] public List<IdName<int>>? Unitrequest { get; set; } // [Parameter] public List<IdName<int>>? Unitrequest { get; set; }
@@ -91,7 +182,6 @@ else
protected override Task OnParametersSetAsync() protected override Task OnParametersSetAsync()
{ {
result = new ActionInResultComponent() result = new ActionInResultComponent()
{ {
Status = ComponentStatus.fild Status = ComponentStatus.fild
@@ -119,7 +209,7 @@ else
public async Task OnClickDelete() public async Task OnClickDelete()
{ {
var rsp = await hc.Delete($"Cod/Delete/{Cod.ID}"); var rsp = await hc.Delete($"Cod/Delete/{invoice.ID}");
if (rsp.IsSuccessStatusCode) if (rsp.IsSuccessStatusCode)
{ {
var request = await rsp.Content.ReadFromJsonAsync<bool>(); var request = await rsp.Content.ReadFromJsonAsync<bool>();
@@ -144,54 +234,58 @@ else
} }
public async Task OnClickUpdate() public async Task OnClickUpdate()
{ {
if (Cod.UnitID > 0 && Cod.TaxRate > 0 && !string.IsNullOrEmpty(Cod.Title)) // if (Cod.UnitID > 0 && Cod.TaxRate > 0 && !string.IsNullOrEmpty(Cod.Title))
{ // {
var rsp = await hc.Put<RCOD>("Cod/Update", Cod); // var rsp = await hc.Put<RCOD>("Cod/Update", Cod);
if (rsp.IsSuccessStatusCode) // if (rsp.IsSuccessStatusCode)
{ // {
var request = await rsp.Content.ReadFromJsonAsync<bool>(); // var request = await rsp.Content.ReadFromJsonAsync<bool>();
if (request) // if (request)
{ // {
result.Status = ComponentStatus.success; // result.Status = ComponentStatus.success;
result.Action = ComponentAction.update; // result.Action = ComponentAction.update;
await OnMultipleOfThree.InvokeAsync(result); // await OnMultipleOfThree.InvokeAsync(result);
} // }
else ShowDangerAlert("خطایی در اجرای عملیات رخ داده"); // else ShowDangerAlert("خطایی در اجرای عملیات رخ داده");
} // }
else // else
{ // {
var request = await rsp.Content.ReadFromJsonAsync<List<string>>(); // var request = await rsp.Content.ReadFromJsonAsync<List<string>>();
ShowDangerAlert(request[0]); // ShowDangerAlert(request[0]);
} // }
} // }
else ShowDangerAlert("فیلدهای قرمز باید مقدار دهی شوند"); // else ShowDangerAlert("فیلدهای قرمز باید مقدار دهی شوند");
} }
public async Task OnClickAdd() public async Task OnClickAdd()
{ {
if (Cod.UnitID > 0 && Cod.TaxRate > 0 && !string.IsNullOrEmpty(Cod.Title)) // if (Cod.UnitID > 0 && Cod.TaxRate > 0 && !string.IsNullOrEmpty(Cod.Title))
{ // {
var rsp = await hc.Post<RCOD>("Cod/Add", Cod); // var rsp = await hc.Post<RCOD>("Cod/Add", Cod);
if (rsp.IsSuccessStatusCode) // if (rsp.IsSuccessStatusCode)
{ // {
var request = await rsp.Content.ReadFromJsonAsync<bool>(); // var request = await rsp.Content.ReadFromJsonAsync<bool>();
if (request) // if (request)
{ // {
result.Status = ComponentStatus.success; // result.Status = ComponentStatus.success;
result.Action = ComponentAction.add; // result.Action = ComponentAction.add;
await OnMultipleOfThree.InvokeAsync(result); // await OnMultipleOfThree.InvokeAsync(result);
} // }
else ShowDangerAlert("خطایی در اجرای عملیات رخ داده"); // else ShowDangerAlert("خطایی در اجرای عملیات رخ داده");
} // }
else // else
{ // {
var request = await rsp.Content.ReadFromJsonAsync<List<string>>(); // var request = await rsp.Content.ReadFromJsonAsync<List<string>>();
ShowDangerAlert(request[0]); // ShowDangerAlert(request[0]);
} // }
} // }
else ShowDangerAlert("فیلدهای قرمز باید مقدار دهی شوند"); // else ShowDangerAlert("فیلدهای قرمز باید مقدار دهی شوند");
}
public async Task<bool> Validate()
{
return false;
} }
} }

View File

@@ -114,7 +114,7 @@
@code { @code {
private string? customerName; private string? customerName;
public IEnumerable<ForCustomerSearch>? customers; public IEnumerable<ForCustomerSearch>? customers;
public List<IdName<int>> Patterns { get; set; }
private async Task<AutoCompleteDataProviderResult<ForCustomerSearch>> CustomersDataProvider(AutoCompleteDataProviderRequest<ForCustomerSearch> request) private async Task<AutoCompleteDataProviderResult<ForCustomerSearch>> CustomersDataProvider(AutoCompleteDataProviderRequest<ForCustomerSearch> request)
{ {
if (customers is null) // pull customers only one time for client-side autocomplete if (customers is null) // pull customers only one time for client-side autocomplete
@@ -210,11 +210,28 @@
} }
public async Task InvoiceItem(int ID) public async Task InvoiceItem(int ID)
{ {
if (customers is null)
customers = await GetCustomers();
if (Patterns == null || Patterns.Count < 0)
{
var rsp = await hc.Get("Invoice/GetPatterns");
if (rsp.IsSuccessStatusCode)
{
Patterns = await rsp.Content.ReadFromJsonAsync<List<IdName<int>>>();
}
}
var parameters = new Dictionary<string, object>(); var parameters = new Dictionary<string, object>();
if (ID == 0) parameters.Add("Invoice", new InvoiceDTO() { ID = 0 }); if (ID == 0) parameters.Add("Invoice", new InvoiceDTO()
{
ID = 0,
InvoiceDate = DateTime.Now.ConvertMiladiToShamsiinFront().ShamciToFormatShamciinFront(),
InvoicIssueDate = DateTime.Now.ConvertMiladiToShamsiinFront().ShamciToFormatShamciinFront(),
Udate = DateTime.Now.ConvertMiladiToShamsiinFront().ShamciToFormatShamciinFront()
});
else parameters.Add("invoice", request.list.Where(w => w.ID == ID).First().Clone()); else parameters.Add("invoice", request.list.Where(w => w.ID == ID).First().Clone());
parameters.Add("Patterns", Patterns);
parameters.Add("Cus", customers);
parameters.Add("OnMultipleOfThree", EventCallback.Factory.Create<ActionInResultComponent>(this, CallBackCustomerItem)); parameters.Add("OnMultipleOfThree", EventCallback.Factory.Create<ActionInResultComponent>(this, CallBackCustomerItem));
await modal.ShowAsync<InvoiceItem>(title: ID == 0 ? "صورتحساب جدید" : "ویرایش اطلاعات", parameters: parameters); await modal.ShowAsync<InvoiceItem>(title: ID == 0 ? "صورتحساب جدید" : "ویرایش اطلاعات", parameters: parameters);

View File

@@ -33,9 +33,9 @@ builder.Services.AddScoped(sp => new UserAuthenticationDTO()
}) ; }) ;
//builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("https://localhost:7075/api/") }); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("https://localhost:7075/api/") });
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("http://localhost:5271/api/") }); //builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("http://localhost:5271/api/") });
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("fa-Ir"); CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("fa-Ir");