diff --git a/public/css/style.css b/public/css/style.css
index ae817d2..dec7aa6 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -434,20 +434,6 @@ button.danger {
font-size: 14px;
}
-.input-with-button {
- display: flex;
- gap: 8px;
-}
-
-.input-with-button input {
- flex: 1;
- margin-bottom: 0;
-}
-
-.input-with-button button {
- white-space: nowrap;
-}
-
.field-hint {
display: block;
font-size: 12px;
diff --git a/public/dashboard/index.html b/public/dashboard/index.html
index 8177a27..7811d6e 100644
--- a/public/dashboard/index.html
+++ b/public/dashboard/index.html
@@ -206,10 +206,7 @@
@@ -273,10 +270,7 @@
diff --git a/public/js/dashboard.js b/public/js/dashboard.js
index 033379e..4684117 100644
--- a/public/js/dashboard.js
+++ b/public/js/dashboard.js
@@ -545,45 +545,38 @@ function formatRobloxUserId(userId) {
return escapeHtml(userId);
}
-// Wires up a "Look up username" button next to a User ID input: on click, prompts for a username,
-// resolves it via the Roblox API, fills the input with the id, and shows a status hint.
-function setupUsernameLookupButton(buttonId, inputId, hintId) {
- const button = document.getElementById(buttonId);
+// Wires up a User ID input so it accepts either a plain numeric id or a Roblox username: on blur,
+// if the current value isn't purely digits, it's treated as a username, resolved to an id via the
+// Roblox API, and the input is rewritten to hold the id (with a status hint shown either way).
+function setupUserIdField(inputId, hintId) {
const input = document.getElementById(inputId);
const hint = document.getElementById(hintId);
- if (!button || !input) return;
+ if (!input || !hint) return;
- button.addEventListener('click', async () => {
- const username = prompt('Enter a Roblox username to look up its user id:');
- if (username === null) return;
- if (!username.trim()) return;
-
- const originalLabel = button.textContent;
- button.textContent = 'Looking up...';
- button.disabled = true;
+ input.addEventListener('blur', async () => {
+ const value = input.value.trim();
hint.classList.add('hidden');
+ if (!value || /^\d+$/.test(value)) return; // Blank, or already a plain numeric id - nothing to resolve.
- try {
- const userId = await lookupRobloxUsername(username);
- if (userId) {
- input.value = userId;
- const user = robloxUserCache.get(userId);
- hint.textContent = `Found: ${user.name} (id ${userId})`;
- hint.className = 'field-hint success';
- } else {
- hint.textContent = `No Roblox user found with username "${username.trim()}"`;
- hint.className = 'field-hint error';
- }
- hint.classList.remove('hidden');
- } finally {
- button.textContent = originalLabel;
- button.disabled = false;
+ hint.textContent = 'Looking up username...';
+ hint.className = 'field-hint';
+ hint.classList.remove('hidden');
+
+ const userId = await lookupRobloxUsername(value);
+ if (userId) {
+ input.value = userId;
+ const user = robloxUserCache.get(userId);
+ hint.textContent = `Found: ${user.name} (id ${userId})`;
+ hint.className = 'field-hint success';
+ } else {
+ hint.textContent = `No Roblox user found with username "${value}"`;
+ hint.className = 'field-hint error';
}
});
}
-setupUsernameLookupButton('acl-data-lookup-btn', 'acl-data', 'acl-data-hint');
-setupUsernameLookupButton('group-member-data-lookup-btn', 'group-member-data', 'group-member-data-hint');
+setupUserIdField('acl-data', 'acl-data-hint');
+setupUserIdField('group-member-data', 'group-member-data-hint');
async function saveReader(readerId, card) {
@@ -1029,7 +1022,18 @@ document.getElementById('add-acl-form').addEventListener('submit', async (e) =>
const type = parseInt(document.getElementById('acl-type').value, 10);
let data;
- if (type === 0 || type === 1) {
+ if (type === 0) {
+ data = document.getElementById('acl-data').value.trim();
+ if (!data) return;
+ if (!/^\d+$/.test(data)) {
+ const userId = await lookupRobloxUsername(data);
+ if (!userId) {
+ alert(`No Roblox user found with username "${data}"`);
+ return;
+ }
+ data = userId;
+ }
+ } else if (type === 1) {
data = document.getElementById('acl-data').value.trim();
if (!data) return;
} else if (type === 2 || type === 3) {
@@ -1230,7 +1234,18 @@ document.getElementById('add-group-member-form').addEventListener('submit', asyn
const type = parseInt(document.getElementById('group-member-type').value, 10);
let data;
- if (type === 0 || type === 1) {
+ if (type === 0) {
+ data = document.getElementById('group-member-data').value.trim();
+ if (!data) return;
+ if (!/^\d+$/.test(data)) {
+ const userId = await lookupRobloxUsername(data);
+ if (!userId) {
+ alert(`No Roblox user found with username "${data}"`);
+ return;
+ }
+ data = userId;
+ }
+ } else if (type === 1) {
data = document.getElementById('group-member-data').value.trim();
if (!data) return;
} else if (type === 2 || type === 3) {