Compare commits

..

2 Commits

Author SHA1 Message Date
morbalint 8abe228d89 [fe] improve first time save UX 2024-01-22 12:51:40 +01:00
morbalint cc9a83607c use the official discord button on registration page as well
and disable the not yet approved external login providers on the registration page
2024-01-21 15:25:37 +01:00
4 changed files with 69 additions and 8 deletions
@@ -116,6 +116,12 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
// Disable not yet approved external login providers in production
if (!_environment.IsDevelopment())
{
ExternalLogins = ExternalLogins.Where(el => el.Name == "Discord").ToList();
}
if (ModelState.IsValid) if (ModelState.IsValid)
{ {
// This doesn't count login failures towards account lockout // This doesn't count login failures towards account lockout
@@ -49,7 +49,8 @@
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal"> <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
<div> <div>
<p> <p>
@foreach (var provider in Model.ExternalLogins!) <button type="submit" class="btn" name="provider" value="Discord" title="Log in using your Discord account"><img height="24px" alt="Discord" src="/img/discord-logo-blue.svg" /></button>
@foreach (var provider in Model.ExternalLogins!.Where(el => el.Name != "Discord"))
{ {
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button> <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
} }
@@ -30,13 +30,15 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
private readonly IUserEmailStore<ApplicationUser> _emailStore; private readonly IUserEmailStore<ApplicationUser> _emailStore;
private readonly ILogger<RegisterModel> _logger; private readonly ILogger<RegisterModel> _logger;
private readonly IEmailSender _emailSender; private readonly IEmailSender _emailSender;
private readonly IWebHostEnvironment _environment;
public RegisterModel( public RegisterModel(
UserManager<ApplicationUser> userManager, UserManager<ApplicationUser> userManager,
IUserStore<ApplicationUser> userStore, IUserStore<ApplicationUser> userStore,
SignInManager<ApplicationUser> signInManager, SignInManager<ApplicationUser> signInManager,
ILogger<RegisterModel> logger, ILogger<RegisterModel> logger,
IEmailSender emailSender) IEmailSender emailSender,
IWebHostEnvironment environment)
{ {
_userManager = userManager; _userManager = userManager;
_userStore = userStore; _userStore = userStore;
@@ -44,6 +46,7 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
_signInManager = signInManager; _signInManager = signInManager;
_logger = logger; _logger = logger;
_emailSender = emailSender; _emailSender = emailSender;
_environment = environment;
} }
/// <summary> /// <summary>
@@ -105,12 +108,22 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
{ {
ReturnUrl = returnUrl; ReturnUrl = returnUrl;
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
// Disable not yet approved external login providers in production
if (!_environment.IsDevelopment())
{
ExternalLogins = ExternalLogins.Where(el => el.Name == "Discord").ToList();
}
} }
public async Task<IActionResult> OnPostAsync(string returnUrl = null) public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{ {
returnUrl ??= Url.Content("~/"); returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
// Disable not yet approved external login providers in production
if (!_environment.IsDevelopment())
{
ExternalLogins = ExternalLogins.Where(el => el.Name == "Discord").ToList();
}
if (!ModelState.IsValid) if (!ModelState.IsValid)
{ {
return Page(); return Page();
@@ -21,7 +21,8 @@ import {CalculateMasodlagosErtekek} from "../domain-models/masodlagos_ertekek";
import {KarakterInputToPdfView} from "../pdf/karakter_pdf_view"; import {KarakterInputToPdfView} from "../pdf/karakter_pdf_view";
import JellemSelector from "../components/JellemSelector"; import JellemSelector from "../components/JellemSelector";
import {CanLevelUp, LevelDown, LevelUp} from "../domain-models/level"; import {CanLevelUp, LevelDown, LevelUp} from "../domain-models/level";
import {Card, OverlayTrigger, Toast, ToastContainer} from "react-bootstrap"; import {Button, Card, InputGroup, Modal, OverlayTrigger, Toast, ToastContainer} from "react-bootstrap";
import Form from "react-bootstrap/Form";
import LevelUps from "../components/LevelUps"; import LevelUps from "../components/LevelUps";
import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpecializacio"; import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpecializacio";
import Felszereles from '../components/Felszereles'; import Felszereles from '../components/Felszereles';
@@ -39,7 +40,6 @@ function CreateCharacterPage(props: {
const {faro} = props const {faro} = props
const loaderData = useLoaderData() as KarakterInputs & { isPublic: boolean } | undefined; const loaderData = useLoaderData() as KarakterInputs & { isPublic: boolean } | undefined;
const initialIsPublic = loaderData?.isPublic ?? false;
let initialKarakterInputs = KarakterDefaults; let initialKarakterInputs = KarakterDefaults;
if (loaderData != null) { if (loaderData != null) {
const { isPublic: t1, ...t2 } = loaderData; const { isPublic: t1, ...t2 } = loaderData;
@@ -47,6 +47,9 @@ function CreateCharacterPage(props: {
} }
const { id } = useParams(); const { id } = useParams();
const fetchedUser = useContext(UserContext); const fetchedUser = useContext(UserContext);
const initialIsPublic = loaderData?.isPublic ?? fetchedUser?.data == null;
const navigate = useNavigate(); const navigate = useNavigate();
let [karakter, changeKarakter] = useState(initialKarakterInputs) let [karakter, changeKarakter] = useState(initialKarakterInputs)
@@ -66,9 +69,25 @@ function CreateCharacterPage(props: {
const canLevelUp = CanLevelUp(karakter) const canLevelUp = CanLevelUp(karakter)
let [showSaveModal, setShowSaveModal] = useState(false);
let [newId, setNewId] = useState(null as string | null)
let [showSaved, setShowSaved] = useState(false); let [showSaved, setShowSaved] = useState(false);
let [isPublic, setIsPublic] = useState(initialIsPublic); let [isPublic, setIsPublic] = useState(initialIsPublic);
const newCharacterUrl = () => `${window.location.origin}/1e/karakter/${newId}`
const handleSaveModalCopyAndClose = async () => {
await navigator.clipboard.writeText(newCharacterUrl());
handleSaveModalClose()
}
const handleSaveModalClose = () => {
setShowSaveModal(false);
navigate(`/1e/karakter/${newId}`)
}
const hideSaved = () => setShowSaved(false); const hideSaved = () => setShowSaved(false);
const onSaveClicked = async () => { const onSaveClicked = async () => {
faro?.api.pushEvent('character_stored', { faro?.api.pushEvent('character_stored', {
@@ -78,9 +97,9 @@ function CreateCharacterPage(props: {
is_public: isPublic.toString(), is_public: isPublic.toString(),
}) })
if (id == null) { if (id == null) {
let newId = await StoreNewCharacter(karakter, isPublic); let recievedId = await StoreNewCharacter(karakter, isPublic);
setShowSaved(true); setNewId(recievedId)
navigate(`/1e/karakter/${newId}`) setShowSaveModal(true);
} else { } else {
await UpdateCharacter(id, karakter, isPublic); await UpdateCharacter(id, karakter, isPublic);
setShowSaved(true); setShowSaved(true);
@@ -97,9 +116,31 @@ function CreateCharacterPage(props: {
</div> </div>
<ToastContainer className="position-fixed" position="top-end"> <ToastContainer className="position-fixed" position="top-end">
<Toast show={showSaved} onClose={hideSaved} bg="success"> <Toast show={showSaved} onClose={hideSaved} bg="success">
<Toast.Header><strong>Karakter mentve!</strong></Toast.Header> <Toast.Body className="text-light">Karakter mentve!</Toast.Body>
</Toast> </Toast>
</ToastContainer> </ToastContainer>
<Modal show={showSaveModal} onHide={handleSaveModalClose}>
<Modal.Header closeButton>
<Modal.Title>Karakter mentve!</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Karaktered az alábbi {isPublic ? 'publikus' : 'privát'} URLen érhető el.</p>
<p><a href={newCharacterUrl()}>{newCharacterUrl()}</a></p>
<InputGroup className="mb-3">
<Form.Control id="input" value={newCharacterUrl()} />
<Button variant={"outline-dark"} onClick={() => {
let copyText = document.querySelector("#input") as any;
copyText?.select()
document.execCommand("copy");
}}>Másolás</Button>
</InputGroup>
</Modal.Body>
<Modal.Footer>
<Button variant="danger" onClick={handleSaveModalCopyAndClose}>
Másolás és bezárás
</Button>
</Modal.Footer>
</Modal>
<div className='p-3'> <div className='p-3'>
<form onSubmit={async (event) => event.preventDefault()}> <form onSubmit={async (event) => event.preventDefault()}>
<div className='row'> <div className='row'>