feat(EnvelopeLocked): Timer mit CSS-Konfiguration und Javascript-Ereignis hinzugefügt.
- Ablauf über Home-Controller-Ansichtsdaten hinzugefügt
This commit is contained in:
parent
cdec5485c6
commit
fa44b82493
@ -2,6 +2,6 @@
|
|||||||
{
|
{
|
||||||
public class CodeGeneratorConfig
|
public class CodeGeneratorConfig
|
||||||
{
|
{
|
||||||
public string CharPool { get; init; } = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
public string CharPool { get; init; } = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789012345678901234567890123456789";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,6 +4,8 @@
|
|||||||
{
|
{
|
||||||
public required bool Ok { get; init; }
|
public required bool Ok { get; init; }
|
||||||
|
|
||||||
|
public DateTime? Expiration { get; set; }
|
||||||
|
|
||||||
public DateTime? AllowedAt { get; set; }
|
public DateTime? AllowedAt { get; set; }
|
||||||
|
|
||||||
public TimeSpan AllowedAfter => Allowed ? TimeSpan.Zero : AllowedAt!.Value - DateTime.Now;
|
public TimeSpan AllowedAfter => Allowed ? TimeSpan.Zero : AllowedAt!.Value - DateTime.Now;
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace EnvelopeGenerator.Application.Services
|
|||||||
|
|
||||||
public static CodeGenerator Static => LazyStatic.Value;
|
public static CodeGenerator Static => LazyStatic.Value;
|
||||||
|
|
||||||
private readonly string _charPool = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
private readonly string _charPool;
|
||||||
|
|
||||||
public CodeGenerator(IOptions<CodeGeneratorConfig> options)
|
public CodeGenerator(IOptions<CodeGeneratorConfig> options)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -61,10 +61,13 @@ namespace EnvelopeGenerator.Application.Services
|
|||||||
code = _codeGen.GenerateCode(_smsParams.CodeLength);
|
code = _codeGen.GenerateCode(_smsParams.CodeLength);
|
||||||
|
|
||||||
await _cache.SetStringAsync(code_key, code, _codeCacheOptions);
|
await _cache.SetStringAsync(code_key, code, _codeCacheOptions);
|
||||||
|
|
||||||
|
var expiration = DateTime.Now + _smsParams.CodeCacheValidityPeriod;
|
||||||
|
await _cache.SetDateTimeAsync(code_expiration_key, expiration, _codeCacheOptions);
|
||||||
|
|
||||||
await _cache.SetDateTimeAsync(code_expiration_key, DateTime.Now + _smsParams.CodeCacheValidityPeriod, _codeCacheOptions);
|
var res = await SendSmsAsync(recipient: recipient, message: code);
|
||||||
|
res.Expiration = expiration;
|
||||||
return await SendSmsAsync(recipient: recipient, message: code);
|
return res;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -191,8 +191,10 @@ namespace EnvelopeGenerator.Web.Controllers
|
|||||||
if (er_secret.HasPhoneNumber)
|
if (er_secret.HasPhoneNumber)
|
||||||
{
|
{
|
||||||
var res = await _msgService.SendSmsCodeAsync(er_secret.PhoneNumber!, envelopeReceiverId: envelopeReceiverId);
|
var res = await _msgService.SendSmsCodeAsync(er_secret.PhoneNumber!, envelopeReceiverId: envelopeReceiverId);
|
||||||
if(res.Ok)
|
if (res.Ok)
|
||||||
return View("EnvelopeLocked").WithData("ViaSms", true);
|
return View("EnvelopeLocked").WithData("ViaSms", true).WithData("Expiration", res.Expiration);
|
||||||
|
else if (!res.Allowed)
|
||||||
|
return View("EnvelopeLocked").WithData("ViaSms", true).WithData("Expiration", res.AllowedAt);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var res_json = JsonConvert.SerializeObject(res);
|
var res_json = JsonConvert.SerializeObject(res);
|
||||||
|
|||||||
@ -47,7 +47,7 @@
|
|||||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||||
<PackageReference Include="BuildBundlerMinifier2022" Version="2.9.9" />
|
<PackageReference Include="BuildBundlerMinifier2022" Version="2.9.9" />
|
||||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="2.2.1" />
|
<PackageReference Include="DigitalData.Core.Abstractions" Version="2.2.1" />
|
||||||
<PackageReference Include="DigitalData.Core.API" Version="2.0.0" />
|
<PackageReference Include="DigitalData.Core.API" Version="2.0.1" />
|
||||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="2.0.0" />
|
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="2.0.0" />
|
||||||
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
|
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
@using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
@using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
|
@using Newtonsoft.Json
|
||||||
@{
|
@{
|
||||||
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
|
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
|
||||||
var logo = _logoOpt.Value;
|
var logo = _logoOpt.Value;
|
||||||
@ -6,6 +7,7 @@
|
|||||||
var userCulture = ViewData["UserCulture"] as Culture;
|
var userCulture = ViewData["UserCulture"] as Culture;
|
||||||
bool viaSms = ViewData["ViaSms"] is bool _viaSms && _viaSms;
|
bool viaSms = ViewData["ViaSms"] is bool _viaSms && _viaSms;
|
||||||
var accessCodeName = viaSms ? "smsCode" : "accessCode";
|
var accessCodeName = viaSms ? "smsCode" : "accessCode";
|
||||||
|
DateTime? expiration = ViewData["Expiration"] is DateTime _expiration ? _expiration : null;
|
||||||
}
|
}
|
||||||
<div class="page container py-4 px-4">
|
<div class="page container py-4 px-4">
|
||||||
<header class="text-center">
|
<header class="text-center">
|
||||||
@ -35,6 +37,10 @@
|
|||||||
login
|
login
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
@if (expiration is not null)
|
||||||
|
{
|
||||||
|
<div id="sms-timer" class="alert alert-primary" role="alert">00:00</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -52,4 +58,30 @@
|
|||||||
<p>@_localizer[viaSms ? WebKey.LockedSmsTfaFooterBody : WebKey.LockedFooterBody]</p>
|
<p>@_localizer[viaSms ? WebKey.LockedSmsTfaFooterBody : WebKey.LockedFooterBody]</p>
|
||||||
</details>
|
</details>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
<script nonce="@nonce">
|
||||||
|
var expiration = new Date(@Html.Raw(JsonConvert.SerializeObject(expiration)));
|
||||||
|
|
||||||
|
const element = document.getElementById("sms-timer");
|
||||||
|
|
||||||
|
const interval = setInterval(function () {
|
||||||
|
var now = new Date();
|
||||||
|
|
||||||
|
var diffInMillis = expiration - now;
|
||||||
|
|
||||||
|
if (diffInMillis <= 0) {
|
||||||
|
element.textContent = "00:00";
|
||||||
|
clearInterval(interval);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var minutes = Math.floor(diffInMillis / 1000 / 60);
|
||||||
|
var seconds = Math.floor((diffInMillis / 1000) % 60);
|
||||||
|
|
||||||
|
var formattedMinutes = minutes.toString().padStart(2, '0');
|
||||||
|
var formattedSeconds = seconds.toString().padStart(2, '0');
|
||||||
|
|
||||||
|
var remainingTime = `${formattedMinutes}:${formattedSeconds}`;
|
||||||
|
element.textContent = remainingTime;
|
||||||
|
}, 1000);
|
||||||
|
</script>
|
||||||
@ -135,6 +135,7 @@
|
|||||||
"Headers": {},
|
"Headers": {},
|
||||||
"QueryParams": {
|
"QueryParams": {
|
||||||
"from": "signFlow"
|
"from": "signFlow"
|
||||||
}
|
},
|
||||||
|
"CodeCacheValidityPeriod": "00:10:00"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -402,14 +402,17 @@ footer#page-footer {
|
|||||||
|
|
||||||
.access-code-form-floating {
|
.access-code-form-floating {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: start;
|
justify-content: space-between;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.access-code-form-floating button {
|
.access-code-form-floating button {
|
||||||
align-content: center;
|
align-content: center;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
|
margin:0;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.access-code-form-floating input {
|
.access-code-form-floating input {
|
||||||
@ -427,6 +430,24 @@ footer#page-footer {
|
|||||||
height: 2.5rem;
|
height: 2.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sms-timer {
|
||||||
|
height: 3rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #007bff;
|
||||||
|
margin: 0 0 0 2rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sms-timer:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/*.flag-dropdown button {
|
/*.flag-dropdown button {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}*/
|
}*/
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -11,7 +11,7 @@ document.querySelectorAll('.email-input').forEach(input => {
|
|||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
var dropdownItems = document.querySelectorAll('.culture-dropdown-item');
|
var dropdownItems = document.querySelectorAll('.culture-dropdown-item');
|
||||||
dropdownItems.forEach(function (item) {
|
dropdownItems.forEach(function (item) {
|
||||||
item.addEventListener('click', async function(event) {
|
item.addEventListener('click', async function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var language = this.getAttribute('data-language');
|
var language = this.getAttribute('data-language');
|
||||||
var flagCode = this.getAttribute('data-flag');
|
var flagCode = this.getAttribute('data-flag');
|
||||||
@ -21,6 +21,30 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const setTimer = (elementId, expirationTime) => {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
|
||||||
|
const interval = setInterval(function () {
|
||||||
|
var now = new Date();
|
||||||
|
|
||||||
|
var diffInMillis = expirationTime - now;
|
||||||
|
|
||||||
|
if (diffInMillis <= 0) {
|
||||||
|
element.textContent = "00:00";
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
var minutes = Math.floor(diffInMillis / 1000 / 60);
|
||||||
|
var seconds = Math.floor((diffInMillis / 1000) % 60);
|
||||||
|
|
||||||
|
var formattedMinutes = minutes.toString().padStart(2, '0');
|
||||||
|
var formattedSeconds = seconds.toString().padStart(2, '0');
|
||||||
|
|
||||||
|
var remainingTime = `${formattedMinutes}:${formattedSeconds}`;
|
||||||
|
element.textContent = remainingTime;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
const bsNotify = (message, options) => alertify.notify(
|
const bsNotify = (message, options) => alertify.notify(
|
||||||
`<div class="alert ${options.alert_type ? 'alert-' + options.alert_type : ''}" role="alert"><span class="material-symbols-outlined">${options?.icon_name ?? ''}</span><p>${message}</p></div>`,
|
`<div class="alert ${options.alert_type ? 'alert-' + options.alert_type : ''}" role="alert"><span class="material-symbols-outlined">${options?.icon_name ?? ''}</span><p>${message}</p></div>`,
|
||||||
'custom',
|
'custom',
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
document.querySelectorAll(".email-input").forEach(n=>{n.addEventListener("input",function(){/^\S+@\S+\.\S+$/.test(this.value)?this.classList.remove("is-invalid"):this.classList.add("is-invalid")})});document.addEventListener("DOMContentLoaded",function(){var n=document.querySelectorAll(".culture-dropdown-item");n.forEach(function(n){n.addEventListener("click",async function(n){n.preventDefault();var t=this.getAttribute("data-language"),i=this.getAttribute("data-flag");document.getElementById("selectedFlag").className="fi "+i+" me-2";await setLanguage(t)})})});const bsNotify=(n,t)=>alertify.notify(`<div class="alert ${t.alert_type?"alert-"+t.alert_type:""}" role="alert"><span class="material-symbols-outlined">${t?.icon_name??""}</span><p>${n}</p></div>`,"custom",t?.delay??5);class Comp{static ActPanel=class{static __Root;static get Root(){Comp.ActPanel.__Root??=document.getElementById("flex-action-panel");return Comp.ActPanel.__Root}static get Elements(){return[...Comp.ActPanel.Root.children]}static get IsHided(){return Comp.ActPanel.Root.style.display=="none"}static set Display(n){Comp.ActPanel.Root.style.display=n;Comp.ActPanel.Elements.forEach(t=>t.style.display=n)}static Toggle(){Comp.ActPanel.Display=Comp.ActPanel.IsHided?"":"none"}};static SignatureProgress=class{static __SignatureCount;static get SignatureCount(){this.__SignatureCount=parseInt(document.getElementById("signature-count").innerText);return this.__SignatureCount}static __SignedCountSpan;static get SignedCountSpan(){this.__SignedCountSpan??=document.getElementById("signed-count");return Comp.SignatureProgress.__SignedCountSpan}static __signedCount=0;static get SignedCount(){return this.__signedCount}static set SignedCount(n){this.__signedCount=n;const t=(n/this.SignatureCount)*100;this.SignedCountBar.style.setProperty("--progress-width",t+"%");this.SignedCountSpan.innerText=n.toString()}static __SignedCountBar;static get SignedCountBar(){this.__SignedCountBar??=document.getElementById("signed-count-bar");return this.__SignedCountBar}};static __ShareBackdrop;static get ShareBackdrop(){return Comp.__ShareBackdrop??=new bootstrap.Modal(document.getElementById("shareBackdrop")),this.__ShareBackdrop}}
|
document.querySelectorAll(".email-input").forEach(n=>{n.addEventListener("input",function(){/^\S+@\S+\.\S+$/.test(this.value)?this.classList.remove("is-invalid"):this.classList.add("is-invalid")})});document.addEventListener("DOMContentLoaded",function(){var n=document.querySelectorAll(".culture-dropdown-item");n.forEach(function(n){n.addEventListener("click",async function(n){n.preventDefault();var t=this.getAttribute("data-language"),i=this.getAttribute("data-flag");document.getElementById("selectedFlag").className="fi "+i+" me-2";await setLanguage(t)})})});const setTimer=(n,t)=>{const i=document.getElementById(n),r=setInterval(function(){var u=new Date,n=t-u;n<=0&&(i.textContent="00:00",clearInterval(r));var f=Math.floor(n/6e4),e=Math.floor(n/1e3%60),o=f.toString().padStart(2,"0"),s=e.toString().padStart(2,"0"),h=`${o}:${s}`;i.textContent=h},1e3)},bsNotify=(n,t)=>alertify.notify(`<div class="alert ${t.alert_type?"alert-"+t.alert_type:""}" role="alert"><span class="material-symbols-outlined">${t?.icon_name??""}</span><p>${n}</p></div>`,"custom",t?.delay??5);class Comp{static ActPanel=class{static __Root;static get Root(){Comp.ActPanel.__Root??=document.getElementById("flex-action-panel");return Comp.ActPanel.__Root}static get Elements(){return[...Comp.ActPanel.Root.children]}static get IsHided(){return Comp.ActPanel.Root.style.display=="none"}static set Display(n){Comp.ActPanel.Root.style.display=n;Comp.ActPanel.Elements.forEach(t=>t.style.display=n)}static Toggle(){Comp.ActPanel.Display=Comp.ActPanel.IsHided?"":"none"}};static SignatureProgress=class{static __SignatureCount;static get SignatureCount(){this.__SignatureCount=parseInt(document.getElementById("signature-count").innerText);return this.__SignatureCount}static __SignedCountSpan;static get SignedCountSpan(){this.__SignedCountSpan??=document.getElementById("signed-count");return Comp.SignatureProgress.__SignedCountSpan}static __signedCount=0;static get SignedCount(){return this.__signedCount}static set SignedCount(n){this.__signedCount=n;const t=(n/this.SignatureCount)*100;this.SignedCountBar.style.setProperty("--progress-width",t+"%");this.SignedCountSpan.innerText=n.toString()}static __SignedCountBar;static get SignedCountBar(){this.__SignedCountBar??=document.getElementById("signed-count-bar");return this.__SignedCountBar}};static __ShareBackdrop;static get ShareBackdrop(){return Comp.__ShareBackdrop??=new bootstrap.Modal(document.getElementById("shareBackdrop")),this.__ShareBackdrop}}
|
||||||
Loading…
x
Reference in New Issue
Block a user