Skip to content

Commit

Permalink
finished welcome and name select screens
Browse files Browse the repository at this point in the history
  • Loading branch information
BenKurrek committed Sep 20, 2024
1 parent 3f0ec58 commit eef6ee5
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 243 deletions.
4 changes: 2 additions & 2 deletions src/components/tickets/ticket-qr-code.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ export default function TicketQRCode({
if (keyInfo.has_scanned === true) {
setEventCredentials(secretKey, userData, false);
if (keyInfo.account_id === null) {
navigate("/welcome");
navigate("/nameselect");
} else {
navigate("/");
navigate("/me");
}
}
};
Expand Down
4 changes: 2 additions & 2 deletions src/constants/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ export const UNAUTHENTICATED_ROUTES = [
"/agenda",
"/help",
"/me/admin",
// Do not modify below
"/welcome",

"/tickets/ticket",
"/scan/tickets",
];

// Routes that should hide the footer
export const HIDDEN_FOOTER_ROUTES = [
"/welcome",
"/nameselect",
"/tickets/ticket",
"/scan/tickets",
"/me/admin",
Expand Down
4 changes: 4 additions & 0 deletions src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ const router = createBrowserRouter([
path: "/welcome",
lazy: lazyWithOfflineCheck(() => import("@/routes/welcome")),
},
{
path: "/nameselect",
lazy: lazyWithOfflineCheck(() => import("@/routes/name-select")),
},
/**
* Sponsor/Admin Routes
*/
Expand Down
182 changes: 182 additions & 0 deletions src/routes/name-select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { KEYPOM_TOKEN_FACTORY_CONTRACT } from "@/constants/common";
import eventHelperInstance from "@/lib/event";
import { useEventCredentials } from "@/stores/event-credentials";
import { Box, Input, Button, VStack, Heading } from "@chakra-ui/react";
import { useState } from "react";
import { useNavigate } from "react-router-dom";

// Regex to validate account ID (NEAR format: lowercase, alphanumeric, _, -, no capital letters)
const accountIdPattern = /^([a-z\d]+[-_])*[a-z\d]+$/;

// Maximum length for username (total 64 - length of factory contract - 1 for the dot)
const maxUsernameLength = 64 - KEYPOM_TOKEN_FACTORY_CONTRACT.length - 1;

export default function SetRecipient() {
const navigate = useNavigate();
const { secretKey } = useEventCredentials();

const [selectedUsername, setSelectedUsername] = useState<string | undefined>(
undefined,
);
const [isValidUsername, setIsValidUsername] = useState<boolean>(true);
const [error, setError] = useState<string>("");
const [isChecking, setIsChecking] = useState<boolean>(false); // For checking username existence
const [isClaiming, setIsClaiming] = useState<boolean>(false);

// Handle invalid characters and length while typing
const handleInputChange = (value: string) => {
const lowerCaseValue = value.toLowerCase();
setSelectedUsername(lowerCaseValue);

if (!lowerCaseValue) {
setIsValidUsername(false);
setError("");
return;
}

if (lowerCaseValue.length > maxUsernameLength) {
setIsValidUsername(false);
setError(`Username must be less than ${maxUsernameLength} characters.`);
return;
}

if (!accountIdPattern.test(lowerCaseValue)) {
setIsValidUsername(false);
setError("The username contains invalid characters");
return;
}

setIsValidUsername(true);
setError("");
};

// Handle blur or "Continue" click - check username existence
const handleCheckUsername = async () => {
if (!isValidUsername) return;

setIsChecking(true); // Indicate that the check is in progress
try {
const doesExist = await eventHelperInstance.accountExists(
`${selectedUsername}.${KEYPOM_TOKEN_FACTORY_CONTRACT}`,
);
console.log("doesExist: ", doesExist);
if (doesExist) {
setError("The chosen name already exists.");
setIsValidUsername(false);
} else {
setError("");
setIsValidUsername(true);
}
return doesExist;
} catch (e) {
console.log(e);
setIsValidUsername(false);
setError("An error occurred while validating the account.");
return false;
} finally {
setIsChecking(false); // Reset checking state
}
};

const handleClick = async () => {
if (!selectedUsername) return;

if (isValidUsername && !isChecking) {
const doesExist = await handleCheckUsername();
if (!doesExist) {
const accountId = `${selectedUsername}.${KEYPOM_TOKEN_FACTORY_CONTRACT}`;
try {
setIsClaiming(true);
await eventHelperInstance.handleCreateEventAccount({
secretKey,
accountId,
});
setIsClaiming(false);
navigate(`/welcome`);
} catch (e) {
setIsClaiming(false);
setError("Error claiming ticket. Please contact support.");
console.error(e);
}
}
}
};

return (
<VStack spacing={4} maxWidth={"100%"}>
<Box
alignItems="center"
display="flex"
flexDirection="column"
px={4}
pt={12}
width="100%"
flexGrow={1}
>
<Heading textAlign="center" size="md" pb="2">
CHOOSE YOUR USERNAME
</Heading>
</Box>
<Box
mt={12}
w="100%"
bg="url(/assets/custom-button-bg.webp) 50% / cover no-repeat"
p={4}
>
<Input
bg="var(--chakra-colors-brand-400)"
color="black"
borderRadius="md"
textAlign="center"
fontWeight="bold"
fontFamily={"mono"}
value={selectedUsername}
type="text"
fontSize="24px"
height="54px"
padding="1rem 0"
autoFocus
onChange={(e) => handleInputChange(e.target.value)} // Check invalid characters as user types
_placeholder={{
color: "black",
opacity: 0.5,
}}
placeholder="@username"
onKeyDown={(e) => {
if (e.key === "Enter" && isValidUsername) {
handleClick();
}
}}
/>
</Box>
<Box w="100%" p={4}>
<Button
isDisabled={!isValidUsername || isChecking}
width="100%"
isLoading={isClaiming}
p={4}
_disabled={{
opacity: 0.5,
cursor: "not-allowed",
}}
variant="primary"
onClick={handleClick}
>
{isChecking ? "Checking..." : "CONTINUE"}
</Button>
</Box>
{error && (
<Box
mt={4}
mx={2}
color="red.400"
textAlign="center"
fontSize="sm"
fontFamily="mono"
>
{error}
</Box>
)}
</VStack>
);
}
4 changes: 2 additions & 2 deletions src/routes/tickets/ticket.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ export default function Ticket() {
if (keyInfo.has_scanned === true) {
setEventCredentials(secretKey, userData, false);
if (keyInfo.account_id === null) {
navigate("/welcome");
navigate("/nameselect");
} else {
navigate("/");
navigate("/me");
}
}

Expand Down
Loading

0 comments on commit eef6ee5

Please sign in to comment.