update toaster LO; add forms where in necessary
This commit is contained in:
@@ -3,7 +3,12 @@ import { useRef, useState } from "react";
|
|||||||
import Arrow from "@/icons/arrow.svg?react";
|
import Arrow from "@/icons/arrow.svg?react";
|
||||||
import Paperclip from "@/icons/paperclip.svg?react";
|
import Paperclip from "@/icons/paperclip.svg?react";
|
||||||
import Clock from "@/icons/clock.svg?react";
|
import Clock from "@/icons/clock.svg?react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { useNavigate } from "@tanstack/react-router";
|
||||||
|
import { useAccountStore } from "@/contexts/AccountContext";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import { useToast } from "@/lib/hooks/use-toast";
|
||||||
|
|
||||||
const Chat = observer(() => {
|
const Chat = observer(() => {
|
||||||
return (
|
return (
|
||||||
@@ -14,6 +19,10 @@ const Chat = observer(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const WelcomePanel = () => {
|
const WelcomePanel = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { userId } = useAccountStore();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-[741px] flex flex-col gap-8">
|
<div className="max-w-[741px] flex flex-col gap-8">
|
||||||
<div className="flex flex-col gap-2 font-medium">
|
<div className="flex flex-col gap-2 font-medium">
|
||||||
@@ -42,6 +51,14 @@ const WelcomePanel = () => {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
key={emoji}
|
key={emoji}
|
||||||
|
onClick={() => {
|
||||||
|
if (userId === undefined) {
|
||||||
|
navigate({
|
||||||
|
to: "/auth/mail",
|
||||||
|
viewTransition: { types: ["warp"] },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
className="text-left cursor-pointer hover:bg-fill-100 transition-all w-[173px] h-[123px] p-4 rounded-[16px] border border-[#E8E8E8] flex flex-col justify-between"
|
className="text-left cursor-pointer hover:bg-fill-100 transition-all w-[173px] h-[123px] p-4 rounded-[16px] border border-[#E8E8E8] flex flex-col justify-between"
|
||||||
>
|
>
|
||||||
<p className="text-[14px] font-medium leading-[120%]">{text}</p>
|
<p className="text-[14px] font-medium leading-[120%]">{text}</p>
|
||||||
@@ -57,6 +74,9 @@ const WelcomePanel = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ChatInput = () => {
|
const ChatInput = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { userId } = useAccountStore();
|
||||||
|
|
||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
const [showShadow, setShowShadow] = useState(false);
|
const [showShadow, setShowShadow] = useState(false);
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
@@ -116,14 +136,20 @@ const ChatInput = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<button
|
<Button
|
||||||
type="button"
|
className="w-10 h-10 rotate-180"
|
||||||
disabled={message.trim() === ""}
|
disabled={message.trim() === ""}
|
||||||
className="w-10 h-10 rounded-[8px] flex items-center justify-center rotate-180 disabled:opacity-50 disabled:cursor-not-allowed"
|
onClick={() => {
|
||||||
style={{ backgroundColor: "#E8E8E8" }}
|
if (userId === undefined) {
|
||||||
|
navigate({
|
||||||
|
to: "/auth/mail",
|
||||||
|
viewTransition: { types: ["warp"] },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Arrow color="white" />
|
<Arrow color="white" />
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const buttonVariants = cva(
|
|||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
primary:
|
primary:
|
||||||
"bg-fill-800 text-white hover:bg-fill-700 disabled:bg-fill-400",
|
"bg-fill-800 text-white hover:bg-fill-700 disabled:bg-fill-200",
|
||||||
secondary:
|
secondary:
|
||||||
"bg-fill-100 text-text-light-900 hover:bg-fill-150 disabled:bg-fill-100 disabled:text-text-light-200",
|
"bg-fill-100 text-text-light-900 hover:bg-fill-150 disabled:bg-fill-100 disabled:text-text-light-200",
|
||||||
tertiary:
|
tertiary:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const TextLink: FC<TextLinkProps> = ({
|
|||||||
<a
|
<a
|
||||||
data-disabled={disabled}
|
data-disabled={disabled}
|
||||||
className={cn(
|
className={cn(
|
||||||
"text-feedback-info-900 data-[disabled=true]:opacity-50 font-[600] data-[disabled=false]:cursor-pointer data-[disabled=false]:hover:border-b-[2px] w-fit transition-all duration-75",
|
"text-feedback-info-900 data-[disabled=true]:opacity-50 font-[500] data-[disabled=false]:cursor-pointer data-[disabled=false]:hover:border-b-[2px] w-fit transition-all duration-75",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ import { cn } from "@/lib/utils";
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { useToast } from "@/lib/hooks/use-toast";
|
import { useToast } from "@/lib/hooks/use-toast";
|
||||||
|
|
||||||
|
import Discord from "@/icons/discord.svg?react";
|
||||||
|
import Copy from "@/icons/copy.svg?react";
|
||||||
|
import { TextLink } from "./text-link";
|
||||||
|
|
||||||
const ToastProvider = ToastPrimitives.Provider;
|
const ToastProvider = ToastPrimitives.Provider;
|
||||||
|
|
||||||
const ToastViewport = React.forwardRef<
|
const ToastViewport = React.forwardRef<
|
||||||
@@ -35,10 +39,10 @@ const toastVariants = cva(
|
|||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
success: "bg-feedback-positive-100",
|
success: "bg-fill-100",
|
||||||
warning: "bg-feedback-attention-100",
|
warning: "bg-fill-100",
|
||||||
error: "bg-feedback-negative-100",
|
error: "bg-fill-100",
|
||||||
info: "bg-feedback-info-100",
|
info: "bg-fill-100",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
@@ -51,7 +55,7 @@ const ToastIcon = React.forwardRef<
|
|||||||
React.ElementRef<typeof ToastPrimitives.Root>,
|
React.ElementRef<typeof ToastPrimitives.Root>,
|
||||||
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
|
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
|
||||||
VariantProps<typeof toastVariants>
|
VariantProps<typeof toastVariants>
|
||||||
>(({ className, variant }) => {
|
>(({ className, variant = "success" }) => {
|
||||||
if (variant === "success") {
|
if (variant === "success") {
|
||||||
return (
|
return (
|
||||||
<SuccessIcon className={clsx(className, "text-feedback-positive-900")} />
|
<SuccessIcon className={clsx(className, "text-feedback-positive-900")} />
|
||||||
@@ -213,7 +217,7 @@ type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
|
|||||||
|
|
||||||
type ToastActionElement = React.ReactElement<typeof ToastAction>;
|
type ToastActionElement = React.ReactElement<typeof ToastAction>;
|
||||||
|
|
||||||
export function Toaster() {
|
function Toaster() {
|
||||||
const { toasts, isPaused, setIsPaused } = useToast();
|
const { toasts, isPaused, setIsPaused } = useToast();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -258,28 +262,12 @@ export function Toaster() {
|
|||||||
>
|
>
|
||||||
<ToastIcon className="size-12 mr-4" variant={props.variant} />
|
<ToastIcon className="size-12 mr-4" variant={props.variant} />
|
||||||
<div className="grid gap-2 w-full">
|
<div className="grid gap-2 w-full">
|
||||||
{title && <ToastTitle>{title}</ToastTitle>}
|
<div className="flex items-center w-full justify-between">
|
||||||
|
{title && <ToastTitle>{title}</ToastTitle>} <ToastClose />
|
||||||
|
</div>
|
||||||
|
|
||||||
{description && (
|
{description && (
|
||||||
<ToastDescription>
|
<ToastDescription>{description}</ToastDescription>
|
||||||
{/* {props.variant === "errorWithCopy" && (
|
|
||||||
<p className="text-[16px] mb-2">
|
|
||||||
To solve problems, contact us <br />
|
|
||||||
via{" "}
|
|
||||||
<a
|
|
||||||
href={"https://discord.gg/cytonic"}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="text-brand relative"
|
|
||||||
>
|
|
||||||
Discord
|
|
||||||
<div className="h-[1px] w-[56px] bg-brand absolute left-0" />
|
|
||||||
</a>{" "}
|
|
||||||
and send the error text
|
|
||||||
</p>
|
|
||||||
)} */}
|
|
||||||
{description}
|
|
||||||
</ToastDescription>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{copy && (
|
{copy && (
|
||||||
@@ -287,7 +275,6 @@ export function Toaster() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{action}
|
{action}
|
||||||
<ToastClose />
|
|
||||||
|
|
||||||
{withTimeline && (
|
{withTimeline && (
|
||||||
<ToastTimeline
|
<ToastTimeline
|
||||||
@@ -304,6 +291,35 @@ export function Toaster() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TOASTER_DESCRIPTION_PATTERNS = {
|
||||||
|
errorPattern: (
|
||||||
|
<div>
|
||||||
|
<span>
|
||||||
|
<p>Please try again later</p>
|
||||||
|
<p className="mt-2">
|
||||||
|
If the problem persists, copy the error message below and contact our
|
||||||
|
support team
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div className="space-x-4 flex">
|
||||||
|
<TextLink className="flex items-center gap-1">
|
||||||
|
<Copy className="text-feedback-info-900" width={15} height={12} />[
|
||||||
|
Error code ]
|
||||||
|
</TextLink>
|
||||||
|
|
||||||
|
<TextLink
|
||||||
|
className="flex items-center gap-1"
|
||||||
|
href="https://discord.gg/cytonic"
|
||||||
|
>
|
||||||
|
<Discord className="text-feedback-info-900" width={15} height={12} />[
|
||||||
|
Support ]
|
||||||
|
</TextLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
type ToastProps,
|
type ToastProps,
|
||||||
type ToastActionElement,
|
type ToastActionElement,
|
||||||
@@ -317,4 +333,6 @@ export {
|
|||||||
ToastIcon,
|
ToastIcon,
|
||||||
ToastCopy,
|
ToastCopy,
|
||||||
ToastTimeline,
|
ToastTimeline,
|
||||||
|
Toaster,
|
||||||
|
TOASTER_DESCRIPTION_PATTERNS,
|
||||||
};
|
};
|
||||||
|
|||||||
3
src/icons/discord.svg
Normal file
3
src/icons/discord.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="24" height="18" viewBox="0 0 24 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19.9831 1.50753C18.4748 0.794022 16.8791 0.287044 15.2381 0C15.0337 0.37359 14.7949 0.87607 14.6303 1.27582C12.8611 1.00684 11.1081 1.00684 9.37143 1.27582C9.20684 0.876161 8.96264 0.37359 8.75636 0C7.11383 0.287168 5.51674 0.795438 4.00767 1.51126C1.00474 6.09907 0.190662 10.5728 0.597654 14.9832C2.5894 16.4869 4.5196 17.4004 6.41728 17.9982C6.88893 17.3425 7.30584 16.6483 7.66368 15.9228C6.98233 15.6605 6.32548 15.3373 5.70096 14.9571C5.86529 14.8339 6.02577 14.7055 6.18216 14.5722C9.96656 16.3618 14.0785 16.3618 17.8178 14.5722C17.9749 14.7047 18.1353 14.833 18.2989 14.9571C17.6734 15.3384 17.0153 15.6622 16.3326 15.9247C16.6925 16.6531 17.1087 17.348 17.579 18C19.4785 17.4023 21.4105 16.4888 23.4022 14.9832C23.8798 9.87048 22.5865 5.43781 19.9831 1.50753ZM8.1793 12.2709C7.04322 12.2709 6.11154 11.1986 6.11154 9.89292C6.11154 8.58722 7.02337 7.51313 8.1793 7.51313C9.33523 7.51313 10.2669 8.58531 10.247 9.89292C10.2488 11.1986 9.33531 12.2709 8.1793 12.2709ZM15.8206 12.2709C14.6845 12.2709 13.7529 11.1986 13.7529 9.89292C13.7529 8.58722 14.6647 7.51313 15.8206 7.51313C16.9766 7.51313 17.9082 8.58531 17.8883 9.89292C17.8883 11.1986 16.9766 12.2709 15.8206 12.2709Z" fill="currentColor"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -12,7 +12,7 @@ import { Route as rootRouteImport } from './routes/__root'
|
|||||||
import { Route as InteractionPanelRouteImport } from './routes/interaction-panel'
|
import { Route as InteractionPanelRouteImport } from './routes/interaction-panel'
|
||||||
import { Route as AuthRouteImport } from './routes/auth'
|
import { Route as AuthRouteImport } from './routes/auth'
|
||||||
import { Route as IndexRouteImport } from './routes/index'
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
import { Route as MailCodeMailCodeRouteImport } from './routes/mail-code/$mail-code'
|
import { Route as MagicLinkMagicLinkRouteImport } from './routes/magic-link/$magic-link'
|
||||||
import { Route as AuthUsernameRouteImport } from './routes/auth/username'
|
import { Route as AuthUsernameRouteImport } from './routes/auth/username'
|
||||||
import { Route as AuthMailRouteImport } from './routes/auth/mail'
|
import { Route as AuthMailRouteImport } from './routes/auth/mail'
|
||||||
import { Route as AuthCodeRouteImport } from './routes/auth/code'
|
import { Route as AuthCodeRouteImport } from './routes/auth/code'
|
||||||
@@ -32,9 +32,9 @@ const IndexRoute = IndexRouteImport.update({
|
|||||||
path: '/',
|
path: '/',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
const MailCodeMailCodeRoute = MailCodeMailCodeRouteImport.update({
|
const MagicLinkMagicLinkRoute = MagicLinkMagicLinkRouteImport.update({
|
||||||
id: '/mail-code/$mail-code',
|
id: '/magic-link/$magic-link',
|
||||||
path: '/mail-code/$mail-code',
|
path: '/magic-link/$magic-link',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
const AuthUsernameRoute = AuthUsernameRouteImport.update({
|
const AuthUsernameRoute = AuthUsernameRouteImport.update({
|
||||||
@@ -60,7 +60,7 @@ export interface FileRoutesByFullPath {
|
|||||||
'/auth/code': typeof AuthCodeRoute
|
'/auth/code': typeof AuthCodeRoute
|
||||||
'/auth/mail': typeof AuthMailRoute
|
'/auth/mail': typeof AuthMailRoute
|
||||||
'/auth/username': typeof AuthUsernameRoute
|
'/auth/username': typeof AuthUsernameRoute
|
||||||
'/mail-code/$mail-code': typeof MailCodeMailCodeRoute
|
'/magic-link/$magic-link': typeof MagicLinkMagicLinkRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
@@ -69,7 +69,7 @@ export interface FileRoutesByTo {
|
|||||||
'/auth/code': typeof AuthCodeRoute
|
'/auth/code': typeof AuthCodeRoute
|
||||||
'/auth/mail': typeof AuthMailRoute
|
'/auth/mail': typeof AuthMailRoute
|
||||||
'/auth/username': typeof AuthUsernameRoute
|
'/auth/username': typeof AuthUsernameRoute
|
||||||
'/mail-code/$mail-code': typeof MailCodeMailCodeRoute
|
'/magic-link/$magic-link': typeof MagicLinkMagicLinkRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
__root__: typeof rootRouteImport
|
__root__: typeof rootRouteImport
|
||||||
@@ -79,7 +79,7 @@ export interface FileRoutesById {
|
|||||||
'/auth/code': typeof AuthCodeRoute
|
'/auth/code': typeof AuthCodeRoute
|
||||||
'/auth/mail': typeof AuthMailRoute
|
'/auth/mail': typeof AuthMailRoute
|
||||||
'/auth/username': typeof AuthUsernameRoute
|
'/auth/username': typeof AuthUsernameRoute
|
||||||
'/mail-code/$mail-code': typeof MailCodeMailCodeRoute
|
'/magic-link/$magic-link': typeof MagicLinkMagicLinkRoute
|
||||||
}
|
}
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
@@ -90,7 +90,7 @@ export interface FileRouteTypes {
|
|||||||
| '/auth/code'
|
| '/auth/code'
|
||||||
| '/auth/mail'
|
| '/auth/mail'
|
||||||
| '/auth/username'
|
| '/auth/username'
|
||||||
| '/mail-code/$mail-code'
|
| '/magic-link/$magic-link'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to:
|
to:
|
||||||
| '/'
|
| '/'
|
||||||
@@ -99,7 +99,7 @@ export interface FileRouteTypes {
|
|||||||
| '/auth/code'
|
| '/auth/code'
|
||||||
| '/auth/mail'
|
| '/auth/mail'
|
||||||
| '/auth/username'
|
| '/auth/username'
|
||||||
| '/mail-code/$mail-code'
|
| '/magic-link/$magic-link'
|
||||||
id:
|
id:
|
||||||
| '__root__'
|
| '__root__'
|
||||||
| '/'
|
| '/'
|
||||||
@@ -108,14 +108,14 @@ export interface FileRouteTypes {
|
|||||||
| '/auth/code'
|
| '/auth/code'
|
||||||
| '/auth/mail'
|
| '/auth/mail'
|
||||||
| '/auth/username'
|
| '/auth/username'
|
||||||
| '/mail-code/$mail-code'
|
| '/magic-link/$magic-link'
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
IndexRoute: typeof IndexRoute
|
IndexRoute: typeof IndexRoute
|
||||||
AuthRoute: typeof AuthRouteWithChildren
|
AuthRoute: typeof AuthRouteWithChildren
|
||||||
InteractionPanelRoute: typeof InteractionPanelRoute
|
InteractionPanelRoute: typeof InteractionPanelRoute
|
||||||
MailCodeMailCodeRoute: typeof MailCodeMailCodeRoute
|
MagicLinkMagicLinkRoute: typeof MagicLinkMagicLinkRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@tanstack/react-router' {
|
declare module '@tanstack/react-router' {
|
||||||
@@ -141,11 +141,11 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof IndexRouteImport
|
preLoaderRoute: typeof IndexRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
'/mail-code/$mail-code': {
|
'/magic-link/$magic-link': {
|
||||||
id: '/mail-code/$mail-code'
|
id: '/magic-link/$magic-link'
|
||||||
path: '/mail-code/$mail-code'
|
path: '/magic-link/$magic-link'
|
||||||
fullPath: '/mail-code/$mail-code'
|
fullPath: '/magic-link/$magic-link'
|
||||||
preLoaderRoute: typeof MailCodeMailCodeRouteImport
|
preLoaderRoute: typeof MagicLinkMagicLinkRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
'/auth/username': {
|
'/auth/username': {
|
||||||
@@ -190,7 +190,7 @@ const rootRouteChildren: RootRouteChildren = {
|
|||||||
IndexRoute: IndexRoute,
|
IndexRoute: IndexRoute,
|
||||||
AuthRoute: AuthRouteWithChildren,
|
AuthRoute: AuthRouteWithChildren,
|
||||||
InteractionPanelRoute: InteractionPanelRoute,
|
InteractionPanelRoute: InteractionPanelRoute,
|
||||||
MailCodeMailCodeRoute: MailCodeMailCodeRoute,
|
MagicLinkMagicLinkRoute: MagicLinkMagicLinkRoute,
|
||||||
}
|
}
|
||||||
export const routeTree = rootRouteImport
|
export const routeTree = rootRouteImport
|
||||||
._addFileChildren(rootRouteChildren)
|
._addFileChildren(rootRouteChildren)
|
||||||
|
|||||||
@@ -101,6 +101,15 @@ function RouteComponent() {
|
|||||||
setResendTimeout(60);
|
setResendTimeout(60);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
const fullCode = code.join("");
|
||||||
|
console.log("Confirm code:", fullCode);
|
||||||
|
navigate({
|
||||||
|
to: "/auth/username",
|
||||||
|
viewTransition: { types: ["warp"] },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-full gap-10 tracking-[-2%] flex-col">
|
<div className="flex items-center justify-center h-full gap-10 tracking-[-2%] flex-col">
|
||||||
<div className="text-brand-gray text-center">
|
<div className="text-brand-gray text-center">
|
||||||
@@ -114,7 +123,15 @@ function RouteComponent() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-10">
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (code.every((c) => c !== "")) {
|
||||||
|
handleSubmit();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="space-y-10"
|
||||||
|
>
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
{code.map((digit, i) => (
|
{code.map((digit, i) => (
|
||||||
<Input
|
<Input
|
||||||
@@ -136,16 +153,9 @@ function RouteComponent() {
|
|||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<Button
|
<Button
|
||||||
|
type="submit"
|
||||||
className="text-[18px] w-full"
|
className="text-[18px] w-full"
|
||||||
disabled={code.some((c) => c === "")}
|
disabled={code.some((c) => c === "")}
|
||||||
onClick={() => {
|
|
||||||
const fullCode = code.join("");
|
|
||||||
console.log("Confirm code:", fullCode);
|
|
||||||
navigate({
|
|
||||||
to: "/auth/username",
|
|
||||||
viewTransition: { types: ["warp"] },
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Confirm
|
Confirm
|
||||||
</Button>
|
</Button>
|
||||||
@@ -165,7 +175,7 @@ function RouteComponent() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,17 +29,19 @@ function RouteComponent() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-6 w-[300px]">
|
<div className="space-y-6 w-[300px]">
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleSubmit();
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Input
|
<Input
|
||||||
label="Email"
|
label="Email"
|
||||||
placeholder="Email@example.com"
|
placeholder="Email@example.com"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
onKeyDown={(e) => {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
handleSubmit();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
</form>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className="text-[18px] w-full"
|
className="text-[18px] w-full"
|
||||||
|
|||||||
@@ -32,17 +32,19 @@ function RouteComponent() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-6 w-[300px]">
|
<div className="space-y-6 w-[300px]">
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleSubmit();
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Input
|
<Input
|
||||||
label="Username"
|
label="Username"
|
||||||
placeholder="Pink Axolotl"
|
placeholder="Pink Axolotl"
|
||||||
value={username}
|
value={username}
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
onKeyDown={(e) => {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
handleSubmit();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
</form>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Button
|
<Button
|
||||||
@@ -55,7 +57,9 @@ function RouteComponent() {
|
|||||||
<Button
|
<Button
|
||||||
variant={"secondary"}
|
variant={"secondary"}
|
||||||
className="text-[18px] w-full"
|
className="text-[18px] w-full"
|
||||||
// onClick={handleSubmit}
|
onClick={() => {
|
||||||
|
navigate({ to: "/", viewTransition: { types: ["warp"] } });
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Skip for now
|
Skip for now
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import { createFileRoute, Link, useNavigate } from "@tanstack/react-router";
|
|||||||
import { TextLink } from "@/components/ui/text-link";
|
import { TextLink } from "@/components/ui/text-link";
|
||||||
import LogoWithText from "@/icons/logo-with-text.svg?react";
|
import LogoWithText from "@/icons/logo-with-text.svg?react";
|
||||||
|
|
||||||
export const Route = createFileRoute("/mail-code/$mail-code")({
|
export const Route = createFileRoute("/magic-link/$magic-link")({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
});
|
});
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { "mail-code": codeFromUrl } = Route.useParams();
|
const { "magic-link": magicLink } = Route.useParams();
|
||||||
|
|
||||||
const [code, setCode] = useState<string[]>(Array(6).fill(""));
|
const [code, setCode] = useState<string[]>(Array(6).fill(""));
|
||||||
const [isAutoSubmitted, setIsAutoSubmitted] = useState(false);
|
const [isAutoSubmitted, setIsAutoSubmitted] = useState(false);
|
||||||
@@ -31,8 +31,8 @@ function RouteComponent() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (codeFromUrl && /^\d{6}$/.test(codeFromUrl)) {
|
if (magicLink && /^\d{6}$/.test(magicLink)) {
|
||||||
const codeArray = codeFromUrl.split("").slice(0, 6);
|
const codeArray = magicLink.split("").slice(0, 6);
|
||||||
setCode(codeArray);
|
setCode(codeArray);
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
@@ -41,7 +41,7 @@ function RouteComponent() {
|
|||||||
|
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}
|
}
|
||||||
}, [codeFromUrl]);
|
}, [magicLink]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (resendTimeout <= 0) {
|
if (resendTimeout <= 0) {
|
||||||
@@ -143,7 +143,7 @@ function RouteComponent() {
|
|||||||
{code.map((digit, i) => (
|
{code.map((digit, i) => (
|
||||||
<Input
|
<Input
|
||||||
key={i}
|
key={i}
|
||||||
id={`code-input-${i}`}
|
id={"code-input-${i}"}
|
||||||
className="w-10 h-10 p-0 text-center text-lg"
|
className="w-10 h-10 p-0 text-center text-lg"
|
||||||
type="text"
|
type="text"
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
Reference in New Issue
Block a user