Skip to content

Commit 378e4dd

Browse files
authored
fix(templates): resolve sign-in modal service issues in Boilerplate #10845 (#10846)
1 parent c8c1c49 commit 378e4dd

File tree

16 files changed

+106
-65
lines changed

16 files changed

+106
-65
lines changed

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/AppDiagnosticModal.razor

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@
170170
IconName="@BitIconName.Up" />
171171
</BitModal>
172172

173-
<BitModal @bind-IsOpen="isLogModalOpen">
174-
<div style="padding:1rem;">
173+
<BitModal @bind-IsOpen="isLogModalOpen" FullSize>
174+
<BitStack style="padding:1rem;">
175175
<BitStack Horizontal AutoHeight VerticalAlign="BitAlignment.Center">
176176
<BitText Typography="BitTypography.H6">Log details</BitText>
177177
<BitButton IconOnly
@@ -187,10 +187,10 @@
187187
OnClick="() => isLogModalOpen = false"
188188
IconName="@BitIconName.ChromeClose" />
189189
</BitStack>
190-
<br />
190+
191191
<BitText Class="log-modal" Color="GetColor(selectedLog?.Level)">
192192
<pre style="margin:0">@GetContent(selectedLog)</pre>
193193
</BitText>
194-
</div>
194+
</BitStack>
195195
</BitModal>
196196
</div>

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/AppDiagnosticModal.razor.Utils.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,13 @@ private async Task ClearCache()
128128

129129
foreach (var item in await cookie.GetAll())
130130
{
131-
await cookie.Remove(item.Name!);
131+
await cookie.Remove(new ButilCookie()
132+
{
133+
Name = item.Name,
134+
Path = "/",
135+
SameSite = SameSite.Strict,
136+
Secure = AppEnvironment.IsDev() is false
137+
});
132138
}
133139

134140
if (AppPlatform.IsBlazorHybrid is false)

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/AppDiagnosticModal.razor.scss

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,8 @@ section {
3131
}
3232

3333
.log-modal {
34+
width: 100%;
3435
overflow: auto;
35-
max-width: 40rem;
36-
max-height: 40rem;
37-
white-space: nowrap;
38-
height: min(20rem, #{$bit-env-height-available} - 4rem);
39-
width: min(40rem, calc(#{$bit-env-width-available} - 2rem));
36+
height: calc(100% - 3rem);
4037
}
4138
}

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/ForgotPasswordPage.razor.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,16 @@ private async Task Submit()
4040
try
4141
{
4242
model.ReturnUrl = ReturnUrlQueryString;
43-
await identityController.SendResetPasswordToken(model, CurrentCancellationToken);
43+
44+
try
45+
{
46+
await identityController.SendResetPasswordToken(model, CurrentCancellationToken);
47+
}
48+
catch (TooManyRequestsExceptions e)
49+
{
50+
SnackBarService.Error(e.Message);
51+
// Let's go to the reset password page anyway.
52+
}
4453

4554
var queryParams = new Dictionary<string, object?>
4655
{

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/OtpPanel.razor

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,26 +27,28 @@
2727
<ValidationMessage For="@(() => Model.Otp)" />
2828
</BitStack>
2929

30-
<BitButton IsLoading="IsWaiting" ButtonType="BitButtonType.Submit">
30+
<BitButton IsLoading="IsWaiting"
31+
IsEnabled="IsWaiting is false"
32+
ButtonType="BitButtonType.Submit">
3133
@Localizer[nameof(AppStrings.Continue)]
3234
</BitButton>
3335

3436
<BitText Typography="BitTypography.Body2">
3537
@Localizer[nameof(AppStrings.OtpResendMessage)]
36-
<BitLink OnClick="WrapHandled(async () => await OnResendOtp.InvokeAsync())">@Localizer[nameof(AppStrings.Resend)]</BitLink>
38+
<BitLink IsEnabled="IsWaiting is false" OnClick="WrapHandled(async () => await OnResendOtp.InvokeAsync())">@Localizer[nameof(AppStrings.Resend)]</BitLink>
3739
</BitText>
3840

3941
@if (hasEmail)
4042
{
4143
<BitStack Horizontal Gap="2rem" HorizontalAlign="BitAlignment.Center">
42-
<BitLink Href="https://www.gmail.com">
44+
<BitLink Href="https://www.gmail.com" Target="_blank">
4345
<BitStack Horizontal>
4446
<BitImage Src="_content/Boilerplate.Client.Core/images/icons/gmail-icon.png" />
4547
<BitText>Open Gmail</BitText>
4648
</BitStack>
4749
</BitLink>
4850

49-
<BitLink Href="https://www.outlook.com">
51+
<BitLink Href="https://www.outlook.com" Target="_blank">
5052
<BitStack Horizontal>
5153
<BitImage Src="_content/Boilerplate.Client.Core/images/icons/outlook-icon.png" />
5254
<BitText>Open Outlook</BitText>

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInModal.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
Color="BitColor.Tertiary"
88
Variant="BitVariant.Text"
99
IconName="@BitIconName.ChromeClose" />
10-
<SignInPanel OnSuccess="OnSuccess" SignInPanelType="SignInPanelType" />
10+
<SignInPanel OnSuccess="OnSuccess" SignInPanelType="SignInPanelType.OtpOnly" />
1111
</BitStack>
1212
</section>

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInModal.razor.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ public partial class SignInModal
44
{
55
[Parameter] public Action? OnClose { get; set; }
66
[Parameter] public Action? OnSuccess { get; set; } // The SignInModalService will show this page as a modal dialog, and this action will be invoked when the sign-in is successful.
7-
[Parameter] public SignInPanelType SignInPanelType { get; set; } = SignInPanelType.Full; // Check out SignInModalService for more details
8-
9-
10-
private string? value;
117

128
private void CloseModal()
139
{

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPage.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
<AppPageData Title="@Localizer[nameof(AppStrings.SignInPageTitle)]" />
77

88
<section>
9-
<SignInPanel />
9+
<SignInPanel SignInPanelType="SignInPanelType.Full" />
1010
</section>

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPanel.razor

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
Placeholder="@Localizer[nameof(AppStrings.PhoneNumberPlaceholder)]" />
5959
<ValidationMessage For="@(() => model.PhoneNumber)" />
6060
}
61-
@if (SignInPanelType is SignInPanelType.Full or SignInPanelType.PasswordOnly)
61+
@if (internalSignInPanelType is SignInPanelType.Full or SignInPanelType.PasswordOnly)
6262
{
6363
<br />
6464
<BitTextField @bind-Value="model.Password"
@@ -87,43 +87,45 @@
8787
{
8888
<BitButton IconOnly
8989
Size="BitSize.Large"
90+
IsLoading="isWaiting"
9091
Variant="BitVariant.Text"
9192
Color="BitColor.Tertiary"
92-
OnClick="PasswordlessSignIn"
93+
IsEnabled="isWaiting is false"
9394
ButtonType="BitButtonType.Button"
94-
IconName="@BitIconName.Fingerprint" />
95+
IconName="@BitIconName.Fingerprint"
96+
OnClick="WrapHandled(PasswordlessSignIn)" />
9597
}
9698
</BitStack>
9799

98-
@if (SignInPanelType is SignInPanelType.Full or SignInPanelType.PasswordOnly)
100+
@if (internalSignInPanelType is SignInPanelType.Full or SignInPanelType.PasswordOnly)
99101
{
100102
<BitButton IsLoading="isWaiting" IsEnabled="isWaiting is false" ButtonType="BitButtonType.Submit">
101103
@Localizer[nameof(AppStrings.Continue)]
102104
</BitButton>
103105
}
104106

105-
@if (SignInPanelType is SignInPanelType.Full or SignInPanelType.OtpOnly)
107+
@if (internalSignInPanelType is SignInPanelType.Full or SignInPanelType.OtpOnly)
106108
{
107-
<BitButton AutoLoading
108-
Variant="BitVariant.Outline"
109+
<BitButton IsLoading="isWaiting"
109110
ButtonType="BitButtonType.Button"
110111
OnClick="WrapHandled(() => SendOtp(resend: true))"
111-
IsEnabled="@(model.Email is not null || model.PhoneNumber is not null)">
112+
Variant="@(internalSignInPanelType is SignInPanelType.OtpOnly ? BitVariant.Fill : BitVariant.Outline)"
113+
IsEnabled="@(isWaiting is false && (model.Email is not null || model.PhoneNumber is not null))">
112114
@(currentTab == SignInPanelTab.Email ? Localizer[nameof(AppStrings.SendMagicLinkButtonText)] : Localizer[nameof(AppStrings.SendOtpButtonText)])
113115
</BitButton>
114116
}
115117

116-
@if (SignInPanelType is SignInPanelType.OtpOnly)
118+
@if (internalSignInPanelType is SignInPanelType.OtpOnly)
117119
{
118-
<BitLink OnClick="() => SignInPanelType = SignInPanelType.PasswordOnly">@Localizer[nameof(AppStrings.SignInByPassword)]</BitLink>
120+
<BitLink OnClick="() => ChangeSignInPanelType(SignInPanelType.PasswordOnly)">@Localizer[nameof(AppStrings.SignInByPassword)]</BitLink>
119121
}
120122

121-
@if (SignInPanelType is SignInPanelType.PasswordOnly)
123+
@if (internalSignInPanelType is SignInPanelType.PasswordOnly)
122124
{
123-
<BitLink OnClick="() => SignInPanelType = SignInPanelType.OtpOnly">@Localizer[nameof(AppStrings.SignInByOtp)]</BitLink>
125+
<BitLink OnClick="() => ChangeSignInPanelType(SignInPanelType.OtpOnly)">@Localizer[nameof(AppStrings.SignInByOtp)]</BitLink>
124126
}
125127

126-
@if (SignInPanelType is SignInPanelType.Full)
128+
@if (internalSignInPanelType is SignInPanelType.Full)
127129
{
128130
<BitText Align="BitTextAlign.Center" Typography="BitTypography.Body2">
129131
@Localizer[nameof(AppStrings.DontHaveAccountMessage)]

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/SignInPanel.razor.cs

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ public partial class SignInPanel
1212
private bool showWebAuthn;
1313
private bool successfulSignIn;
1414
private bool requiresTwoFactor;
15+
private SignInPanelTab currentTab;
1516
private Action? pubSubUnsubscribe;
1617
private JsonElement? webAuthnAssertion;
17-
private SignInPanelTab currentTab;
18+
private SignInPanelType internalSignInPanelType;
1819
private readonly SignInRequestDto model = new();
1920
private AppDataAnnotationsValidator? validatorRef;
2021
private string ReturnUrl => ReturnUrlQueryString ?? NavigationManager.GetRelativePath() ?? Urls.HomePage;
@@ -39,8 +40,7 @@ public partial class SignInPanel
3940
public string? ErrorQueryString { get; set; }
4041

4142
[Parameter] public Action? OnSuccess { get; set; } // The SignInModalService will show this page as a modal dialog, and this action will be invoked when the sign-in is successful.
42-
[Parameter] public SignInPanelType SignInPanelType { get; set; } = SignInPanelType.Full; // Check out SignInModalService for more details
43-
43+
[Parameter] public SignInPanelType SignInPanelType { get; set; } // Check out SignInModalService for more details
4444

4545
[AutoInject] private IWebAuthnService webAuthnService = default!;
4646
[AutoInject] private ILocalHttpServer localHttpServer = default!;
@@ -52,6 +52,8 @@ protected override async Task OnInitAsync()
5252
{
5353
await base.OnInitAsync();
5454

55+
internalSignInPanelType = SignInPanelType;
56+
5557
model.UserName = UserNameQueryString;
5658
model.Email = EmailQueryString;
5759
model.PhoneNumber = PhoneNumberQueryString;
@@ -103,6 +105,8 @@ private async Task DoSignIn()
103105
isWaiting = true;
104106
successfulSignIn = false;
105107

108+
await InvokeAsync(StateHasChanged); // Social sign-in callback will eventually call this method, so we need to update the UI immediately. See ClientPubSubMessages.SOCIAL_SIGN_IN references.
109+
106110
try
107111
{
108112
if (requiresTwoFactor && string.IsNullOrWhiteSpace(model.TwoFactorCode)) return;
@@ -200,6 +204,7 @@ private async Task DoSignIn()
200204
finally
201205
{
202206
isWaiting = false;
207+
await InvokeAsync(StateHasChanged); // Social sign-in callback will eventually call this method, so we need to update the UI immediately. See ClientPubSubMessages.SOCIAL_SIGN_IN references.
203208
}
204209
}
205210

@@ -215,20 +220,29 @@ private async Task SocialSignIn(string provider)
215220
var queryIndex = uri!.IndexOf('?');
216221
var queryParams = AppQueryStringCollection.Parse(uri[queryIndex..]);
217222

223+
string? GetValue(object? value)
224+
{
225+
var valueAsString = value?.ToString();
226+
227+
if (string.IsNullOrEmpty(valueAsString)) return null;
228+
229+
return Uri.UnescapeDataString(valueAsString);
230+
}
231+
218232
queryParams.TryGetValue("return-url", out var returnUrl);
219-
ReturnUrlQueryString = returnUrl?.ToString() ?? Urls.HomePage;
233+
ReturnUrlQueryString = GetValue(returnUrl ?? Urls.HomePage);
220234
queryParams.TryGetValue("userName", out var userName);
221-
UserNameQueryString = userName?.ToString();
235+
UserNameQueryString = GetValue(userName);
222236
queryParams.TryGetValue("email", out var email);
223-
EmailQueryString = email?.ToString();
237+
EmailQueryString = GetValue(email);
224238
queryParams.TryGetValue("phoneNumber", out var phoneNumber);
225-
PhoneNumberQueryString = phoneNumber?.ToString();
239+
PhoneNumberQueryString = GetValue(phoneNumber);
226240
queryParams.TryGetValue("otp", out var otp);
227-
OtpQueryString = otp?.ToString();
241+
OtpQueryString = GetValue(otp);
228242
queryParams.TryGetValue("error", out var error);
229-
ErrorQueryString = error?.ToString();
243+
ErrorQueryString = GetValue(error);
230244

231-
await OnInitAsync();
245+
await InvokeAsync(OnInitAsync);
232246
});
233247

234248
var port = localHttpServer.EnsureStarted();
@@ -245,7 +259,6 @@ private async Task SocialSignIn(string provider)
245259

246260
private async Task PasswordlessSignIn()
247261
{
248-
if (isWaiting) return;
249262
isWaiting = true;
250263

251264
try
@@ -290,6 +303,8 @@ private async Task SendOtp(bool resend)
290303
{
291304
try
292305
{
306+
isWaiting = true;
307+
293308
CleanModel();
294309

295310
if (model.Email is null && model.PhoneNumber is null) return;
@@ -325,12 +340,17 @@ private async Task SendOtp(bool resend)
325340
{
326341
SnackBarService.Error(e.Message);
327342
}
343+
finally
344+
{
345+
isWaiting = false;
346+
}
328347
}
329348

330349
private async Task SendTfaToken()
331350
{
332351
try
333352
{
353+
isWaiting = true;
334354
if (webAuthnAssertion.HasValue is false)
335355
{
336356
CleanModel();
@@ -350,6 +370,10 @@ await identityController
350370
{
351371
SnackBarService.Error(e.Message);
352372
}
373+
finally
374+
{
375+
isWaiting = false;
376+
}
353377
}
354378

355379
private void CleanModel()
@@ -400,4 +424,9 @@ private async Task OnTabChange(BitPivotItem item)
400424
{
401425
currentTab = Enum.Parse<SignInPanelTab>(item.Key!);
402426
}
427+
428+
private async Task ChangeSignInPanelType(SignInPanelType type)
429+
{
430+
internalSignInPanelType = type;
431+
}
403432
}

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignIn/TfaPanel.razor

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
AutoComplete="@BitAutoCompleteValue.OneTimeCode"
2323
Placeholder="@Localizer[nameof(AppStrings.TwoFactorRecoveryCode)]" />
2424

25-
<BitButton IsLoading="IsWaiting" ButtonType="BitButtonType.Submit">
25+
<BitButton IsLoading="IsWaiting" IsEnabled="IsWaiting is false" ButtonType="BitButtonType.Submit">
2626
@Localizer[nameof(AppStrings.Continue)]
2727
</BitButton>
2828

@@ -32,9 +32,10 @@
3232
<BitStack>
3333
<BitText>@Localizer[nameof(AppStrings.TfaPanelAnotherWayTitle)]</BitText>
3434
<BitText Color="BitColor.SecondaryForeground">@Localizer[nameof(AppStrings.TfaPanelAnotherWaySubtitle)]</BitText>
35-
<BitButton AutoLoading
35+
<BitButton IsLoading="IsWaiting"
3636
Color="BitColor.Tertiary"
3737
Variant="BitVariant.Outline"
38+
IsEnabled="IsWaiting is false"
3839
ButtonType="BitButtonType.Button"
3940
OnClick="WrapHandled(OnSendTfaToken.InvokeAsync)">
4041
@Localizer[nameof(AppStrings.TfaPanelAnotherWayGetCode)]

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignUp/SignUpPage.razor.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ private async Task DoSignUp()
4545
{
4646
NavigateToConfirmPage();
4747
}
48+
catch (TooManyRequestsExceptions e)
49+
{
50+
SnackBarService.Error(e.Message);
51+
NavigateToConfirmPage();
52+
}
4853
catch (KnownException e)
4954
{
5055
var message = e is ResourceValidationException re

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthManager.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,13 @@ private async Task ClearTokens()
219219
await storageService.RemoveItem("refresh_token");
220220
if (AppPlatform.IsBlazorHybrid is false)
221221
{
222-
await cookie.Remove("access_token");
222+
await cookie.Remove(new ButilCookie()
223+
{
224+
Name = "access_token",
225+
Path = "/",
226+
SameSite = SameSite.Strict,
227+
Secure = AppEnvironment.IsDev() is false
228+
});
223229
}
224230
NotifyAuthenticationStateChanged(Task.FromResult(await GetAuthenticationStateAsync()));
225231
}

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SignInModalService.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ public async Task<bool> SignIn()
3131

3232
Dictionary<string, object> signInParameters = new()
3333
{
34-
{ nameof(SignInModal.SignInPanelType), SignInPanelType.OtpOnly },
3534
{ nameof(SignInModal.OnClose), () => { signInModalTcs.SetResult(false); modalReference?.Close(); } },
3635
{ nameof(SignInModal.OnSuccess), () => { signInModalTcs.SetResult(true); modalReference?.Close(); } },
3736
};

0 commit comments

Comments
 (0)